CakePHP makes building web applications
simpler, faster and require less code.

News | Development | Documentation

News

News and Releases

Queries log for your AJAX requests

Queries log for your AJAX requests

Have you ever needed to look inside what’s going on with your AJAX requests?

With the rise of javascript-heavy applications it is becoming necessary to have more powerful tools for inspecting and debugging asynchronous requests without reloading the browser or using special browser plugins.

With DebugKit 3.1, inspecting XHR requests is now possible. By default, all AJAX requests are logged into the History panel in your DebugKit Toolbar:

DebugKit Ajax Panel

By clicking on any of the logged XHR requests you will be able to see toolbar information for that specific request, including the SQL log, view variables, logged messages and timers.

This update is immediately available for all CakePHP 3.0.x users, please update your DebugKit installation by doing:

composer update cakephp/debug_kit

We hope this feature will make you as happy and excited as we are. Keep baking!

published on Apr 26, 2015 12:00 AM

Read more

CakePHP 2.6.4 and 3.0.2 Released

CakePHP 2.6.4 and 3.0.2 Released

The CakePHP core team is proud to announce the immediate availability of CakePHP 2.6.4 and 3.0.2. Both releases are bug fix releases for their respective branches.

2.6.4

A short list of the changes you can expect in 2.6.4 is:

  • When json_encode() fails in JsonView an exception is raised.
  • PaginatorHelper will not emit notice errors when generating links for models that were not paginated.
  • Memcache cache engine can now connect to domains starting with ‘u’. Previously, these values were treated as unix sockets.
  • The regression around vendor paths introduced in 2.6.3 has been fixed.
  • HttpSocket can now connect to HTTPS sites via a HTTP Proxy.
  • Sessions are renewed even when the session id is ‘0’.
  • Hash::maxDimensions() now works with arrays of 1 or 0 dimensions.
  • Inflector now correctly inflects ‘sieves’.
  • DboSource::__destruct() now correctly rolls back any open transactions. This restores behavior that was unintentionally removed in an earlier 2.x release.
  • CakeRequest::header() now correctly reads headers with a value of ‘’ and ‘0’.
  • ControllerTestCase now works better with actions that use CakeResponse::file(). Previously warnings were emitted about ob_end_clean() failing.
  • API documentation improvements.

3.0.2

A short list of the changes you can expect in 3.0.2 is:

  • SessionHelper is deprecated. You should use the FlashHelper, or $this->request->session() instead.
  • Saving BelongsToMany associations that contain a mixture of new and existing records has been improved.
  • Validation::notEmpty() has been renamed to Validation::notBlank(). Validation::notEmpty() is now deprecated.
  • Validation::userDefined() is now deprecated, you can set callables directly in the Validator objects instead.
  • SQLite schema reflection now works with older versions of SQLite. Foreign key update/delete clauses will not be reflected with older versions of SQLite.
  • Hash::get() no longer raises an exception on a path of '' or null.
  • Fatal errors when saving belongsToMany relationships that were not marshaled into entities have been fixed.
  • Collection now implements __debugInfo().
  • Magic finder methods now correctly alias fields in the where clause.
  • Cascading deletes now prioritize associations with cascading callbacks, and then apply to associations without callbacks.
  • Shells dispatched with dispatchShell() no longer output the welcome message.
  • MySQL driver now uses SET NAMES to fix encoding errors in some installations.
  • IntegrationTestCase now recursively merges request data into the stubbed request.
  • Responses in IntegrationTestCase now allow better content-type assertions.
  • 0000-00-00 is now converted into null by the database type system. This prevents issues in how PHP’s DateTime handles year 0.
  • FormHelper fields that use integers as their name no longer trigger black hole errors.

CakeFest 2015 Tickets

There is still time to get your tickets for CakeFest 2015 if you haven’t already. May 28th and CakePHP’s 10th anniversary are quickly approaching.

I’d like to thank the people who have contributed to these releases. Your issues, documentation edits, and patches/pull requests are a big part of what keeps CakePHP alive and ticking. Download a packaged release on github.

published on Apr 18, 2015 12:00 AM

Read more

CakePHP 3.0.1 Released

CakePHP 3.0.1 Released

The CakePHP core team is proud to announce the immediate availability of CakePHP 3.0.1. 3.0.1 is a bugfix release for the 3.0 release branch. A short list of the changes you can expect is:

  • Reduced chances for timing attacks in HMAC comparisons in Security::decrypt() by using more constant time string comparisons.
  • FormHelper now supports an idPrefix option. This option allows you to specify the prefix you want prepended to id attribute of all inputs FormHelper generates.
  • FormHelper now supports group templates for each input type. For example, the radioFormGroup template will be used for radio button sets.
  • Elements included in a prefixed request context now look in prefixed paths. When a controller runs in a prefixed route/namespace it will automatically append the current prefix to the view paths used to locate elements.
  • Schema reflection for Postgres no longer fails when foreign keys rely on stored procedures.
  • Schema reflection now treats money columns as strings. Due to leading currency codes the ORM cannot easily map this type into float values.
  • Selectboxes disable and select active options correctly now when complex option data is used.
  • Selectboxes can now have an empty name attribute.
  • URL filters are applied before the existing request context is applied now.
  • CakeI18nTime now supports short timezone offset formats.
  • Query logging now works when the duplicate named parameters are used.
  • existsIn rules now correctly set an error message when used with a list of fields.
  • RulesChecker methods can now return strings to indicate failure. The returned strings will be used as the error message if a field was also defined for the rule.
  • Primary key values can now be defined when creating entities. This improves compatibility with UUID’s where ID’s are generated outside of your application.
  • When saving/updating entities, existing HasMany associations can be re-linked using a _ids input similar to BelongsToMany associations.
  • Greatly improved performance around hydrating ORM results.
  • Improved PHP7 & HHVM compatibility.
  • Improved API documentation.

There is still time to get your tickets for CakeFest 2015 if you haven’t already. May 28th and CakePHP’s 10th anniversary are quickly approaching.

You can view the full changelog on cakephp.org. I’d like to thank the people who have contributed to this release. Your bug tickets, documentation edits, and patches/pull requests are a big part of what keeps CakePHP alive and ticking. Download a packaged release on github.

published on Apr 4, 2015 12:00 AM

Read more

CakeFest 2015: New York, USA

CakeFest 2015: New York, USA

Join us at CakeFest 2015, the annual CakePHP conference, held this year in New York, USA, from the 28th until the 31st of May, and experience the very best of Open Source! Visit http://cakefest.org for info and tickets.

The biggest CakePHP event, ever!

This year we’re celebrating the stable release of 3.0, as well as an incredible 10 years of CakePHP and Open Source with the whole community. This is a huge milestone for the project, so we couldn’t think of anywhere better than the awesome city of New York, USA.

Workshops

The 2 days of workshops at CakeFest are the perfect opportunity to learn the best parts of CakePHP 3.0 with core developers, and a great way to get up to speed with all the new features included in the latest major version of the framework. You’ll also receive your own certificate of attendance.

This year we have both basic and advanced workshops, from getting the most out of CakePHP, to going deep into the internals of the framework, allowing both beginners and veterans to get a piece of the cake!

Conference

Covering 2 full days of keynotes, presentations and talks on CakePHP and related technologies, the conference portion of CakeFest is an event you don’t want to miss, for both enthusiasts and newcomers to the framework. It’s a unique time to engage and network with the community, learn from other experienced developers, and hang out with the core team! See http://cakefest.org/schedule for more details.

Sponsors

This year we’ve teamed up again with some of the biggest names in the industry, to make this the best CakePHP and Open Source community conference ever! These people, organisations and companies help make everything happen, so be sure to check them out at http://cakefest.org/sponsors and say hi!

Event

The event itself is held from Thursday the 28th until Sunday the 31st of May. The first 2 days are dedicated to the workshops, while the weekend sees the 2 conference days through to the closing of the conference.

There are tickets for only the workshops, just the conference days, or the full event (recommended), and we currently have the Early Bird discount on all prices. Grab your tickets now at http://cakefest.org/tickets, and see you there!

published on Mar 31, 2015 12:00 AM

Read more

CakePHP 3.0.0 is Here!

CakePHP 3.0.0 is Here!

The CakePHP team is thrilled to announce the immediate availability of version 3.0.0 stable.

The CakePHP core team is thrilled to announce the release of CakePHP 3.0.0. This is the first API stable release for the 3.0 branch. This release is a backwards incompatible release with previous CakePHP versions. The new minimum requirements for CakePHP are:

  • PHP 5.4.16 or greater.
  • mbstring extension
  • intl extension

Some of the key features in CakePHP 3.0 are outlined in the following sections.

Key Features

A New ORM

The largest and most exciting change in CakePHP 3.0, is the new ORM. While the Model layer in CakePHP has served the community very well for the past 8 years, we felt there was a big opportunity to learn from the tools other frameworks provide and create a flexible and powerful ORM for CakePHP. We are very proud of the results. The ORM migration guide gives an overview of the new ORM, and how it differs from the old one.

Some of the key features of the new ORM are:

Faster and More Flexible Routing

Reverse routing has almost consistent time complexity now. In previous releases reverse routing performance decreased as the number of routes increased. Thanks to named routes and some additional optimizations, routing performance will not degrade even with large numbers of routes.

With the usage of routing scopes, routes can also be parsed and dispatched even faster than in previous releases of CakePHP. You can learn more about the new Router in the Routing section of the manual.

Improved Migrations

A more powerful migrations plugin based on phinx allows you to easily create and deploy migrations for your application.

Better Internationalization

The I18n subsystem was completely rewritten to take advantage of the intl PHP extension. This allows CakePHP to offer:

Improved Debugging Toolbar

DebugKit has been rebuilt for 3.0 and offers more features than ever before with less overhead to your application. DebugKit is installed by default in the new application skeleton.

DebugKit History Panel

Composer Usage

CakePHP, the Application skeleton and several components (bake, acl, migrations and DebugKit are now installed with composer. We recommend using composer for installing CakePHP as it greatly simplifies maintaining the dependencies for your application.

Standalone libraries

A number of CakePHP libraries have been split out into standalone libraries. Each of these libraries can be used outside of CakePHP applications, or in a 2.x application where you want to start leveraging some of the new features in 3.0.

View Cells

View cells are small classes that offer controller-like functionality but can be used directly in the view to pull data from any source and render certain template. Read more about View Cells.

Getting started

On top of the framework changes, we’ve created a new repository for the application skeleton[3]. You can install this and the development preview of CakePHP using composer[4]. After downloading and installing composer you can use:

$php composer.phar create-project cakephp/app

This will generate a new application, so you can start experimenting with CakePHP 3.0.

Learn More With the Documentation

Once you have an application started, you can read the quickstart guide or migration guide to learn more about all the changes and new abilities in CakePHP 3.0.

Community Plugins

Even though CakePHP 3.0 is young, it already counts on a big community behind it. A big list of plugins has been created for this new version and some of the favorite plugins that are used for version 2 have already been upgraded. You can check the list of CakePHP 3 community plugins. To get an overview of what is available and what still needs to be upgraded to the new version.

This new release of CakePHP has been a few years in the making and we’re very thankful for all the help we’ve received. From documentation edits, to pull requests and bug reports, we’ve been impressed with the level of community involvement starting from before the first development preview.

Download a packaged release or get started with the quickstart guide.

published on Mar 22, 2015 12:00 AM

Read more

CakePHP 2.6.3 Released

CakePHP 2.6.3 Released

The CakePHP core team is proud to announce the immediate availability of CakePHP 2.6.3.

The CakePHP core team is proud to announce the immediate availability of CakePHP 2.6.3. 2.6.3 is a bugfix release for the 2.6 release branch. A short list of the changes you can expect is:

  • The postgres driver can now convert text fields into integer fields through SchemaShell.
  • Files with .. in their name can now be downloaded through CakeResponse.
  • LC_TIME messages are ignored when extracting messages via the I18nShell. Previously, incompatible po files were extracted for LC_TIME messages.
  • Fence post errors were fixed in CakeEmail when sending messages with lines equal to 999 bytes.
  • Words with WWW in the middle are no longer autolinked by TextHelper.
  • PaginatorComponent now handles order conditions like Model::find() does.
  • Maxlength attributes are no longer generated by FormHelper for decimal fields. In 2.6.2 maxlength was corrected, however, the fix added in 2.6.2 made it impossible to use the full length of decimal columns.
  • The limit and maxLimit settings for PaginatorComponent are now independent.
  • Model’s whitelist is no longer empty in afterSave.
  • Class names in Scaffold errors are now correct.

The schedule for CakeFest 2015 has been posted. Get your tickets now as May 28th and CakePHP’s 10th anniversary are quickly approaching.

You can view the full changelog on cakephp.org. I’d like to thank the people who have contributed to this release. Your bug tickets, documentation edits, and patches/pull requests are a big part of what keeps CakePHP alive and ticking. Download a packaged release on github.

published on Mar 16, 2015 12:00 AM

Read more

CakePHP 2.6.2 Released

CakePHP 2.6.2 Released

The CakePHP core team is proud to announce the immediate availability of CakePHP 2.6.2.

The CakePHP core team is proud to announce the immediate availability of CakePHP 2.6.2. 2.6.2 is a bugfix release for the 2.6 release branch. A short list of the changes you can expect is:

  • Fixed exception rendering when ExceptionRenderer raised an error.
  • Notice errors in PaginatorHelper when no model was set have been fixed.
  • ConsoleOutput does not generate errors when used with php://output.
  • Redirect responses now use 302 as the default status code instead of 200.
  • Plugin bake now generates correct directories for Views/Layouts.
  • FormHelper no longer creates invalid maxlength attributes for decimal columns when the text type is forced.
  • TextHelper no longer doubly links urls starting with //
  • POT file generation no longer includes the ‘POT-Creation-Date’ header. It often lead to pointless noise in version control.

You can view the full changelog on cakephp.org. I’d like to thank the people who have contributed to this release. Your bug tickets, documentation edits, and patches/pull requests are a big part of what keeps CakePHP alive and ticking. Download a packaged release on github.

published on Feb 19, 2015 12:00 AM

Read more

CakePHP 3.0.0-RC2 Released

CakePHP 3.0.0-RC2 Released

The CakePHP core team is excited to announce the release of CakePHP 3.0.0-RC2.

The CakePHP core team is excited to announce the release of CakePHP 3.0.0-RC2. Our plan is that this will be the final 3.0.0 release candidate and in ~6 weeks time 3.0.0 stable will be released. Since 3.0.0-RC1, we’ve been hard at work incorporating community feedback, fixing many issues and improving the documentation.

Upgrading From an Earlier 3.0.0 release

When upgrading from an earlier 3.0.0 release there are a few important changes you’ll need to make.

Plugin Installation

The use and role of the CakePHP Plugin installer has changed and requires the following updates to your app’s composer.json file:

"require": {
    "cakephp/plugin-installer": "*",
    "cakephp/bake": "dev-master"
},
"scripts": {
    "post-autoload-dump": "Cake\\Composer\\Installer\\PluginInstaller::postAutoloadDump"
}

These additions will ensure that your plugins continue to install correctly. Plugins installed with composer will now be installed under /vendor. This change was done to make the separation between external and in-app plugins clearer. Having both in the same directory was confusing for a number of users.

String renamed to Text

In preparation for PHP7 and HHVM, the String class was renamed to CakeUtilityText. The old class name continues to work but will be removed in a future 3.x release.

Configuration File Changes

Configuration files loaded through Configure::load() previously required the extension. The extension being present made switching configuration file formats hard. For RC2, you must remove the extensions. So Configure::read(‘app.php’) is now Configure::read(‘app’). PHP based configuration files should now return their data instead of setting the $config variable. The $config variable is now deprecated and will be removed in a future 3.x release.

ORM Callback Consistency

The various ORM callbacks had somewhat inconsistent types used for the $options parameter. All callbacks will now receive an ArrayObject for the $options parameter. Query::formatResults() no longer gets the query as an argument either. If you need access to the query from a result formatter, use a closure.

EventManager::detach() and EventManager::attach() are deprecated

These methods have been replaced with on() and off(). These new methods use an interface much like jQuery’s methods. attach() and detach() are now deprecated and will be removed in a future 3.x release. We’d like to welcome Jad Bitar (jadb), Walther Lalk (dakota) and Anthony Grassiot (antograssiot) to the core team. Each of them has helped make 3.0.0 what it is today.

For more details on all the changes in 3.0.0, you should consult the migration guide. In closing, we’d like to thank all of the people that have helped so far with the 3.0 release. Download a packaged release.

published on Feb 9, 2015 12:00 AM

Read more

CakePHP 2.6.1 Released

CakePHP 2.6.1 Released

The CakePHP core team is proud to announce the immediate availability of CakePHP 2.6.1.

The CakePHP core team is proud to announce the immediate availability of CakePHP 2.6.1. 2.6.1 is a bugfix release for the 2.6 release branch. A short list of the changes you can expect is:

  • I18nShell now correctly extracts messages with context.
  • Improved web test runner. All URL options now have links in the interface.
  • Session directories are now created when debug is enabled.
  • Text columns in SQLServer no longer contain length when reflected. The length value was not useful and was causing FormHelper to misbehave.
  • AssetDispatcher no longer sets the Content-Length header as it was incorrect when assets included PHP code.
  • URL autolinking has been improved.
  • Criterion is now correctly inflected.
  • Time strings are now correct when mbstring is not installed.
  • The exception emitted when headers were sent has been removed. This exception was causing more problems than it was solving, including infinite loops on fatal error pages.
  • Radio buttons that are only partially disabled are now added to the list of secured fields.
  • MySQL now correctly quotes SET column values.

You can view the full changelog on cakephp.org. We’d like to thank the people who have contributed to this release. Your bug tickets, documentation edits, and patches/pull requests are a big part of what keeps CakePHP alive and ticking. Download a packaged release on github.

published on Jan 16, 2015 12:00 AM

Read more

CakePHP 3.0.0-RC1 Released

CakePHP 3.0.0-RC1 Released

Was is the best way to start a new year? Having the most advanced and flexible version of CakePHP ready to be used in your projects!

The CakePHP core team is proud to announce the first release candidate for CakePHP 3.0.0. It’s been an intense time since our last beta release. We have been busy polishing most of the rough edges that we could find with the help of the community.

This polishing sprint meant a few breaking API breaking changes from beta3, specifically around the validation subsystem, due to many shortcomings found in the previous implementation.

Below the list of new features and changes that made it into 3.0.0-rc1:

Revamped Validation

The validation process was split into two stages. The first stage is a user-facing type of validation and has not changed since the last release except for where and when it is performed.

In previous versions you would do

 `
$article=$this->Articles->newEntity($this->request->data);
$this->Articles->save($article,['validate'=>'myCustomValidatorName']);

`

But now, user-facing validation is performed when creating the entity and not when saving it. This requires you to pass the validation option to either newEntity or patchEntity methods:

 `
$article=$this->Articles->newEntity($this->request->data,[
'validate'=>'myCustomValidatorName'
]);
$this->Articles->save($article);

`

It is important to notice that fields that fail validation will not be copied into the resulting entity.

The second validation step, that we have called “application rules”, is done when saving or deleting an entity. The rules checking step is meant to check application integrity, such as uniqueness of a column, arity or foreignKey constraints:

 `
//InUsersTable.php

publicfunctionbuildRules(RulesChecker$rules){
$rules->add($rules->isUnique('email'));
return$rules;
}

`

Application rules can also be used to enforce business logic constraints such as state machines, and workflow states.

The validate() and validateMany() methods have been removed from the Table class.

You can read more about the application rules system in the rules checker documentation.

New Error Pages

The error pages containing the exception stack traces have been redesigned to be easier to read and spot what caused the error originally. The new look was inspired by the Rails’ better errors plugin

New Bake Plugin

The cake bake command is now a plugin. This will help us evolve its code at a higher pace and introduce new code generators and configuration options.

One important change concerning bake is that it now uses CakePHP’s View system to render the templates. This means that it is possible to attach listeners to the Bake.beforeRender and Bake.afterRender events to modify bake’s output.

Additionally, the templating syntax has changed to make them more readable. If you had your own bake templates in the past, they will need to be updated to use the new syntax which uses erb style tags. To get the Bake plugin run:

 `
composerrequirecakephp/bake=dev-master--dev

`

And load it in your application bootstrap_cli.php file:

Plugin::load(‘Bake’);

Table-less Forms

Due to popular request, there is now a Form object that is capable of defining a schema and validating form data without the use of ORM tables or entities:

 `
publicfunctionadd()
{
$contact=newContactForm();
if($this->request->is('post')){
if($contact->execute($this->request->data)){
$this->Flash->success('Wewillgetbacktoyousoon.');
return$this->redirect(['action'=>'add']);
}
$this->Flash->error('Therewasaproblemsubmittingyourform.');
}
$this->set('contact',$contact);
}

`

You can read more about them here http://book.cakephp.org/3.0/en/core-libraries/form.html

Adopted PSR-2

We have recently adopted the PSR-2 coding style standard for CakePHP and all the official plugins. You can read more about the reasoning in this blog post

ORM Related Improvements

  • Added Query::firstOrFail()
  • Allowing to change the joinType in TranslateBehavior
  • Implemented Table::addAssociations() to add multiple associations at once
  • Support for IS NOT operator
  • It is now possible to call matching() and contain() for the same association alias.

We’d like to thank again everyone who has contributed thoughts, code, documentation or feedback to 3.0 so far. Please help us find any issues or rough edges in the code by opening tickets in Github.

published on Jan 2, 2015 12:00 AM

Read more

CakePHP Community 2014

CakePHP Community 2014

2014 again beat everyone’s expectations, with the CakePHP community growing around the world.

3.0: the evolution of a PHP framework

If anything were to have marked 2014 for CakePHP we’d probably all agree it was 3.0, the latest major version of the framework in it’s 10 year lifetime. After a series of successful developer previews and several beta releases, we’re now in position to freeze the API inline for a final stable version, just after community review of the release candidates.

It’s been a long way to get where we are right now, but the direction taken has advanced the framework, and brought it inline with what developers have been asking for. There have been some significant changes and great new additions, as well as some important decisions, but we truly feel this best represents the community’s expectations as a whole, and prepares us for the next generation of CakePHP applications.

So far, this year has seen 30+ releases, including versions 2.5 and 2.6 of the framework, and over 120 releases to date. This was made possible by some 290 contributors to the project, and that doesn’t even count the more than 360 contributors to the documentation. Above all, CakePHP continues to be ranked in the top 5 most popular PHP frameworks on GitHub by developers.

The project has also begun to increase it’s modularity even further by splitting the core framework into modules (or packages), which allow aspects of CakePHP to be remixed with other projects. This hasn’t stopped people from being inspired by the framework in the past, even Doctrine gave us a hat tip with their Inflector class. All in all, this just shows how committed we really are about contributing back to the Open Source community as a whole, while allowing developers to use the best of CakePHP where they see fit.

The community effect

On the social side of things we now have over 15,000 likes on Facebook as well as some 12,000 followers on Twitter. There were also various book released this year, accompanied by the launch of both the official podcast and certification platform by the Cake Software Foundation.

We saw some great talks and presentations on CakePHP, numerous interviews and podcasts, lots of blog posts and many tutorials, developers giving their own personal experiences with the project, as well as a community curated list of awesomeness and some stunning displays of contribution growth and developer dedication. We’ve also witnessed the community grow in terms of developer organized meetups, with events now taking place in locations such as the Netherlands, France, Germany, Ahmedabad, Tokyo and New York.

A conference to remember

On the topic of events, CakeFest 2014, the annual CakePHP conference, was held this year in Madrid, Spain. The event, covering 4 days of workshops and conference, left us with lots of memorable moments. It also had some really amazing reviews as well as some awesome feedback from the community.

It was by far one of our biggest turn-outs ever, with an incredible line-up of high profile speakers, and an awesome array of sponsors, including CakeDC, Microsoft Azure, GitHub, Rackspace, O’Reilly, JetBrains, Packt Publishing, NuSphere, Loadsys, SANIsoft, ZenServ, Broadband Finder and Intersective.

The slides for the community keynote are available, or you can listen to it on an episode of the CakePHP podcast. More talks and slides from the conference days can also be found here, or check out images from the event. And finally, a big shout-out to everyone who joined us for 2014, we hope to see you all again next year for another incredible gathering of the CakePHP community!

Drawing to a close

Looking back, this year has been a remarkable year for us. Without a doubt, and after 10 long years, CakePHP still remains a very popular framework for PHP development. It’s the direct result of a community working together!

If you’ve contributed to the project, in any manner, shape or form, then feel proud that you’ve played a part in this awesome social experiment we call Open Source. Words aren’t enough to express our gratitude, so all we can say is... Thank You.

published on Dec 29, 2014 12:00 AM

Read more

CakePHP 2.6.0 Released

CakePHP 2.6.0 Released

The CakePHP core team is proud to announce the immediate availability of CakePHP 2.6.0.

The CakePHP core team is proud to announce the immediate availability of CakePHP 2.6.0. There have been a few changes to 2.6.0 since the RC1 release:

  • AuthComponent now fires the Auth.afterIdentify event after users are logged in.
  • HtmlHelper::script() and HtmlHelper::css() no longer share a single asset list for the once option.
  • Postgres driver supports sslmode.
  • The test suite can now use PHPUnit’s phar file.
  • The RLIKE operator is now supported by the MySQL driver.
  • API documentation improvements
  • PaginatorHelper now merges options used for active links with options used for disabled links.

New Feature Highlight

  • stackTrace() has been added as a convenience wrapper function for Debugger::trace(). It directly echos just as debug() does. But only if debug level is on.
  • ConsoleOptionParser::removeSubcommand() was added.
  • Shell::overwrite() has been added to allow generating progress bars or to avoid outputting too many lines by replacing text that has been already outputted to the screen.
  • When using AclBehavior, The model’s parentNode() method now gets the type (Aro, Aco) passed as first argument: $model->parentNode($type).
  • Schema migrations with MySQL now support an after key when adding a column. This key allows you to specify which column the new one should be added after.
  • Model::save() had the atomic option back-ported from 3.0.
  • CakeRequest::param() can now read values using :ref: hash-path-syntax like data().
  • CakeRequest:setInput() was added.
  • HttpSocket::head() was added.
  • You can now use the protocol option to override the specific protocol to use when making a request.
  • CakeTime::timeAgoInWords() now supports strftime() compatible absolute date formats. This helps make localizing formatted times easier.
  • CakeTime::timeAgoInWords() now supports a relativeStringFuture option. This option is a printf compatible string for outputting future relative time date formats. This helps make localizing formatted times easier.
  • Hash::get() now raises an exception when the path argument is invalid.
  • Hash::nest() now raises an exception when the nesting operation results in no data.
  • HtmlHelper::css() had the once option added. It works the same as the once option for HtmlHelper::script(). The default value is false to maintain backwards compatibility.
  • The maxlength attribute will now also be applied to textareas, when the corresponding DB field is of type varchar, as per HTML specs.
  • New i18n functions have been added. The new functions allow you to include message context which allows you disambiguate possibly confusing message strings. For example ‘read’ can mean multiple things in English depending on the context. The new __x, __xn, __dx, __dxn, __dxc, __dxcn, and __xc functions provide access to the new features.
  • AuthComponent now triggers the Auth.afterIdentify event after successfully identifying a user.
  • Model::afterFind() now always uses a consistent format for afterFind(). When $primary is false, the results will always be located under $data[0][‘ModelName’]. You can set the $this->useConsistentAfterFind = false to restore the original behaviour if your application relies on the old behavior.
  • Configure value I18n.preferApp can now be used to control the order of translations. If set to true it will prefer the app translations over any plugins’ ones.

Deprecations

In addition to new features, a few features have been deprecated, and will be removed in CakePHP 3.0.0

  • Validation::between has been deprecated, you should use Validation::lengthBetween instead.
  • Validation::ssn has been deprecated and may be provided as standalone/plugin solution.
  • The $confirmMessage argument of HtmlHelper::link() has been deprecated. You should instead use key confirm in $options to specify the message.
  • The $confirmMessage argument of FormHelper::postLink() has been deprecated. You should instead use key confirm in $options to specify the message.

The Future of 2.x

With 2.6.0 released, the development branch for 2.7.0 has been created. This branch will be released in 5-6 months and will be another 2.x API compatible release. While the core team doesn’t have any large improvements planned for 2.7, there will be some efforts to backport useful features from 3.0 to help you migrate more easily.

A huge thanks to all involved in terms of both contributions through commits, tickets, documentation edits, and those whom have otherwise contributed to the framework. Without you CakePHP wouldn’t be possible.

published on Dec 23, 2014 12:00 AM

Read more

CakePHP 2.5.8 released

CakePHP 2.5.8 released

The CakePHP core team is proud to announce the immediate availability of CakePHP 2.5.8.

The CakePHP core team is proud to announce the immediate availability of CakePHP 2.5.8. 2.5.8 is a bugfix release for the 2.5 release branch. A short list of the changes you can expect is:

  • Improved error messages when fixtures are missing fields.
  • Human is now properly pluralized by Inflector
  • TreeBehavior regression introduced in 2.5.7 was fixed.
  • RequestHandler::startup() failures no longer prevent error pages from rendering. This could happen when custom input parsers were used.
  • Fixture baking will now ignore unconventional tables instead of stopping.
  • Importing schema from MySQL tables using timestamp columns now works better.

With the release of 2.6.0 complete, this will be the last release of 2.5.x barring any security related issues.

You can view the full changelog on cakephp.org. I’d like to thank the people who have contributed to this release. Your bug tickets, documentation edits, and patches/pull requests are a big part of what keeps CakePHP alive and ticking. Download a packaged release on github.

published on Dec 23, 2014 12:00 AM

Read more

CakePHP 3 to fully adopt PSR-2

CakePHP 3 to fully adopt PSR-2

As of version 3, the framework will fully adopt PSR-2 as a PHP community standard

As many in the community know, since the very beginning CakePHP has maintained and adhered to its own coding standard. Since the creation of CakePHP however, other coding standards have arisen with wider adoption among the PHP community as a whole. To increase consistency with other PHP projects, the core team has decided to fully adopt PSR-2, starting with the release of 3.0.0.

This was not a light decision, and involved much internal debate within the team; we’re all individuals with our own personal preferences, but collectively we agree that the benefits of adopting PSR-2 outweigh our personal editor preferences. We already have an A+ rating for our existing coding conventions, of which 99% conform to the same as other major PHP projects.

Why change this now?

As noted a few months ago, an RFC was suggested to bring the framework more inline with common practices, accepted as a general consensus by the global PHP community. This spurned a long debate over the standards used and why, and who prefers what and when. From this discussion, and seeing the varied points of view, we decided to hold a core vote on whether to fully adopt PSR-2 as a standard, and therefore end our history of partial adoption.

Of course, this change does NOT mean that you have to write your application following the PSR-2 standard. You can in fact choose any coding standard or conventions which align with your style and approach as a programmer. There are even some variations of the PSR-2 standard, if you prefer. This change is mostly oriented towards the coding style of the framework’s core and extended code base, and if desirable, that of community plugins as well.

What are the benefits?

By adopting PSR-2 we can remove or reduce the code we maintain related to enforcing coding standards - as there are common tools, used by the rest of the community, to validate and revise CS issues, without requiring exceptions.

For new users coming to CakePHP, they will have the warm fuzzy feeling of seeing code formatted in a way they are familiar with.

It also allows any effort exerted to discussing why we maintain our own coding standard, which differs from PSR-2, to instead be dedicated to fixing bugs or adding functionality to CakePHP. And, if you’re a developer who uses various frameworks, you’ll no longer have to handle these in your IDE or deployment system to contemplate the edge cases CakePHP introduced.

Our decision to make this announcement now, and separately from a release, is to prepare the community for this change to come, and allow us to advance the process of adapting our existing code bases where necessary.

published on Dec 16, 2014 12:00 AM

Read more

CakePHP 2.5.7 released

CakePHP 2.5.7 released

The CakePHP core team is proud to announce the immediate availability of CakePHP 2.5.7. 2.5.7 is a bugfix release for the 2.5 release branch.

The CakePHP core team is proud to announce the immediate availability of CakePHP 2.5.7. 2.5.7 is a bugfix release for the 2.5 release branch. A short list of the changes you can expect is:

  • Unsetting the email address pattern in CakeEmail now works as documented.
  • Console tools now exit non-zero on failure.
  • Fixed inflection of schema class names in SchemaShell.
  • SQLite datasource correctly parses field names out of queries containing subqueries.
  • TreeBehavior now works with models that have a default order property defined.
  • HttpSocket gracefully handles invalid chunked responses now.
  • HttpSocket now honors the version config option, allowing HTTP 1.0 connections to be made.
  • Postgres datasource now works with sequences defined outside schemas.
  • CakeEmail no longer strips lines that only contain ‘0’.
  • Fix more segfaults in Memcached cache engine.
  • Cached file_map no longer regenerates on every request.
  • CakePHP is now compatible with the phpunit.phar package.
  • Improved API docs, specifically around triggered events.

You can view the full changelog on cakephp.org. I’d like to thank the people who have contributed to this release. Your bug tickets, documentation edits, and patches/pull requests are a big part of what keeps CakePHP alive and ticking. Download a packaged release on github.

published on Dec 9, 2014 12:00 AM

Read more

CakePHP 3.0.0-beta3 released

CakePHP 3.0.0-beta3 released

The CakePHP core team is excited to announce the release of CakePHP 3.0.0-beta3. While we had originally planned on only doing 2 beta releases, we’re not entirely satisfied with the current ORM validation workflow, and want to do some additional work there. The new plan is to have at least two RC releases after beta3. The RC releases will be API frozen and no new features or breaking changes will be added.

The CakePHP core team is excited to announce the release of CakePHP 3.0.0-beta3. While we had originally planned on only doing 2 beta releases, we’re not entirely satisfied with the current ORM validation workflow, and want to do some additional work there. The new plan is to have at least two RC releases after beta3. The RC releases will be API frozen and no new features or breaking changes will be added.

Since 3.0.0-beta2, we’ve been hard at work incorporating community feedback, and completing the remaining changes that will break compatibility in a significant way.

Breaking Changes since 3.0.0-beta2
  • Bake templates now use a templating mechanism that involves a pre- parsing steps of the templates. This was done to improve the readability and ease of creating new bake templates. This also means that any custom templates that you may have will need to be updated.
  • The default replacement for Inflector::slug() is now - instead of _.
  • LOG_ERROR and TESTS constants were unused and have been removed.
  • Controller::$actions was removed and replaced with Controller::isAction(). The new method makes it easier to customize which methods your controllers consider to be routable actions.
  • Component::initialize() is now a post-constructor hook like all other initialize methods.
  • Component has a new beforeFilter() event listener that is fired before a controllers’ beforeFilter method is.
  • CakeSession::read() returns null in all failure scenarios now.
  • Controller actions invoked with requestAction() must return a Response object now. All other return values will trigger an error.
  • Database configuration no longer accepts the ‘login’ key. You must use ‘username’. This was changed to resolve inconsistencies across the framework.
  • Checkbox and radio inputs are now nested inside their attached label elements. This was done to improve compatibility with a few popular CSS libraries. If you have customized the templates FormHelper uses, you may need to update your templates.
  • CakeViewErrorMissingViewException is now CakeViewErrorMissingTemplateException in order to allow MissingView to be used for missing view classes.
  • Authentication objects that had implemented logout() need to be updated to use the new Auth.logout event.
  • The App.www_root configuration value has been renamed to App.wwwRoot for consistency reasons.
New features since 3.0.0-beta2
  • CakeCacheEngineFileEngine now generates directories when debug is off.
  • There are several new standalone libraries extracted from CakePHP. The Cache, Log, Utility packages are now installable separately with composer.
  • The pj() (print json) helper method has been added as a convenience when working in the interactive console or test cases.
  • The Model.initialize event has been added. This event is fired right after a table’s initialize hook has completed, allowing plugins or other listeners to interact with table objects.
  • Database connections, cache engines, loggers and email transports can now be configured with a Datasource Name (DSN) using the url key. This makes it easier to define configuration in environment variables which is a recommended approach by many Platform as a service providers.
  • Component::initialize() and View::initialize() were added.
  • Arbitrary meta tags can be created with HtmlHelper::meta().
  • Exceptions are now raised when custom view class cannot be found.
  • Request data marshaled into entities is not forcibly cast now. This makes validating entity data a bit easier as entity data more closely represents the original request data.
  • The query expression builder now has a between() method for generating BETWEEN clauses.
  • CakeORMBehavior::initialize() was added.
  • Stack traces are now displayed on fatal errors if xdebug is installed.
  • Request::is() now caches results in memory.
  • AuthComponent has two new events. Auth.afterIdentify is fired after a user is identified or logged in. Auth.logout is fired when AuthComponent::logout() is called.
  • SessionComponent is deprecated. Instead you should be using $this->request->session() instead.
  • Each hasher in the FallbackHasher class can have separate options now.

For more details on all the changes in 3.0.0, you can consult the migration guide. In closing, we’d like to thank all of the people that have helped so far with the 3.0 release. We’ve made great progress and without your help we wouldn’t be here today.

Download a packaged release.

published on Nov 17, 2014 12:00 AM

Read more

CakePHP 2.5.6 and 2.6.0-RC released

CakePHP 2.5.6 and 2.6.0-RC released

The CakePHP core team is proud to announce the immediate availability of CakePHP 2.5.6 and 2.6.0-RC1.

The CakePHP core team is proud to announce the immediate availability of CakePHP 2.5.6 and 2.6.0-RC1. 2.5.6 is a bugfix release for the 2.5 release series, while 2.6.0-RC1 is beta release of the upcoming 2.6.0 release. A list of the changes you can expect in 2.5.6 are:

  • CakeSession::read() returns null on all failure cases.
  • Model::isUnique() now works as validator for multiple fields.
  • CakeTestCase::getMockForModel() now injects the test datasource for all connection names.
  • Digest Auth now handles &, ` ?` in digest auth data.
  • FormHelper no longer generates a hidden input for disabled mulitple checkbox inputs.
  • Folder::create() now handles relative paths.
  • Stack traces now output more context on exceptions.
  • Fatal errors now include stack traces if xdebug is enabled.
  • Virtual fields no longer incorrectly replace ` IN` clauses.

Changes in 2.6.0-RC

In addition to the changes in 2.5.6, 2.6.0-RC contains the following changes:

  • Hash::merge() and Hash::expand() are now more performant.
  • TranslateBehavior properly handles the atomic flag.
  • Redis Engine now includes a default prefix based on your application directory.
  • MySQL schema reflection includes comment support now.
  • CakeRoute::__set_state was added. This helps make it easier to cache routes with var_export.
  • CakeResponse::file() accepts ranges even when the download option is set to false.
  • AuthComponent now has a userFields option which allows you to limit which fields are loaded into the session.
  • PaginatorHelper::meta() has been added. This method helps you easily generate meta tags containing pagination information.

If there are no blocking issues found in the RC release we expect to have a stable 2.6.0 release ready in 3 or 4 weeks.

A huge thanks to all involved in terms of both contributions through commits, tickets, documentation edits, and those whom have otherwise contributed to the framework.

published on Nov 8, 2014 12:00 AM

Read more

CakePHP 2.5.5 and 2.6.0-beta released

CakePHP 2.5.5 and 2.6.0-beta released

The CakePHP core team is proud to announce the immediate availability of CakePHP 2.5.5 and 2.6.0-beta.

The CakePHP core team is proud to announce the immediate availability of CakePHP 2.5.5 and 2.6.0-beta. 2.5.5 is a bugfix release for the 2.5 release series, while 2.6.0-beta is beta release of the upcoming 2.6.0 release. A list of the changes you can expect in 2.5.5 are:

  • Console applications will not output colours if there is no TTY.
  • Files are not overwritten by Folder::copy() when the SKIP flag is used.
  • Hash::insert() and Hash::get() now handle 0 as the first path element.
  • Improved API documentation.
  • Fixed a situation where Hash::remove() would remove data incorrectly.
  • UUID columns are now reflected properly by postgres.
  • CakeEmail::reset() now resets the email pattern.
  • Hash::expand() and Hash::merge() are now much faster.

New features in 2.6

Like all the other 2.x releases, 2.6.0 will be backwards compatible with previous versions of CakePHP 2.x, and include a number of new enhancements and improvements. Here is what you can expect in 2.6.0:

  • stackTrace() has been added as a convenience wrapper function for Debugger::trace(). It directly echos just as debug() does. But only if debug level is on.
  • ConsoleOptionParser::removeSubcommand() was added.
  • Shell::overwrite() has been added to allow generating progress bars or to avoid outputting too many lines by replacing text that has been already outputted to the screen.
  • When using AclBehavior, The model’s parentNode() method now gets the type (Aro, Aco) passed as first argument: $model->parentNode($type).
  • Schema migrations with MySQL now support an after key when adding a column. This key allows you to specify which column the new one should be added after.
  • Model::save() had the atomic option back-ported from 3.0.
  • CakeRequest::param() can now read values using :ref: hash-path-syntax like data().
  • CakeRequest:setInput() was added.
  • HttpSocket::head() was added.
  • You can now use the protocol option to override the specific protocol to use when making a request.
  • CakeTime::timeAgoInWords() now supports strftime() compatible absolute date formats. This helps make localizing formatted times easier.
  • CakeTime::timeAgoInWords() now supports a relativeStringFuture option. This option is a printf compatible string for outputting future relative time date formats. This helps make localizing formatted times easier.
  • Hash::get() now raises an exception when the path argument is invalid.
  • Hash::nest() now raises an exception when the nesting operation results in no data.
  • HtmlHelper::css() had the once option added. It works the same as the once option for HtmlHelper::script(). The default value is false to maintain backwards compatibility.
  • The maxlength attribute will now also be applied to textareas, when the corresponding DB field is of type varchar, as per HTML specs.
  • New i18n functions have been added. The new functions allow you to include message context which allows you disambiguate possibly confusing message strings. For example ‘read’ can mean multiple things in English depending on the context. The new __x, __xn, __dx, __dxn, __dxc, __dxcn, and __xc functions provide access to the new features.

A long standing issue in the Model class has been fixed. Because it may be construed as API changes, there is a flag to restore the original behaviour.

  • Model::afterFind() now always uses a consistent format for afterFind(). When $primary is false, the results will always be located under $data[0][‘ModelName’]. You can set the useConsistentAfterFind property to false on your models to restore the original behaviour.

In addition to new features, a few features have been deprecated, and will be removed in CakePHP 3.0.0

  • Validation::between has been deprecated, you should use Validation::lengthBetween instead.
  • Validation::ssn has been deprecated and may be provided as standalone/plugin solution.
  • The $confirmMessage argument of HtmlHelper::link() has been deprecated. You should instead use key confirm in $options to specify the message.
  • The $confirmMessage argument of FormHelper::postLink() has been deprecated. You should instead use key confirm in $options to specify the message.

If the beta release doesn’t have any major issues reported, you can expect an release candidate in ~1 month, with a stable release shortly afterwards.

A huge thanks to all involved in terms of both contributions through commits, tickets, documentation edits, and those whom have otherwise contributed to the framework.

published on Oct 5, 2014 12:00 AM

Read more

CakePHP 3.0.0-beta2 released

CakePHP 3.0.0-beta2 released

One month after our first beta release we are ready to ship the next batch of features.

The CakePHP core team is proud to announce the second beta release for CakePHP 3.0.0. It’s been a month since our first beta release, and we are excited by the big welcome the community has given to the new version. All the positive feedback and help has been a great motivation for the core team to work harder on improving the developer experience for 3.0.

This will be the last beta release for 3.0, this means that the API is already stabilizing and we’re mostly focusing on polishing the current features, performance optimizations, documentation and quickly solving any issues reported in Github.

We’ve had a very busy month implementing a few missing features we had in our roadmap and upgrading some of the popular plugins for CakePHP.

Below the list of new features and changes that made it into 3.0.0-beta2:

DebugKit

Debugging CakePHP 3.0 applications is even better. The new DebugKit is easier to install, faster and looks gorgeous.

DebugKit is a application toolbar that collects useful statistics about your code such as time and memory, executed queries, log messages and view variables. To install Debugkit just use

 `
composerrequirecakephp/debug_kit"3.0.*-dev"

`

And add this line to your bootstrap.php file:

Plugin::load('DebugKit', ['bootstrap' => true]);

If you install a new application using the app skeleton, DebugKit will be automatically installed for you.

Database Migrations

Migrations is now an official CakePHP plugin. It wraps the excellent Phinx library into a CakePHP shell to avoid repeating configuration strings and add some of the cake experience. A database migration generated by this plugin would look like:

<?php
use Phinx\Migration\AbstractMigration;
class CreateUsersTable extends AbstractMigration {
    /**
     * Change.
     */
    public function change() {
        // create the table
        $table = $this->table('users');
        $table->addColumn('id', 'integer')
            ->addColumn('username', 'string')
            ->addColumn('password', 'string')
            ->addColumn('created', 'datetime')
            ->create();
    }

Migrations are reversible. This means that with the same code you can create or rollback the changes done to the database schema.

To install the Migrations plugins run:

 `
composerrequirecakephp/migrations"dev-master"

`

And add this line to your bootstrap.php file:

Plugin::load('Migrations');

New Logger interface

CakePHP has adopted the PSR-3 recommendation for loggers. Now all log engines implement the ` PrsLogLoggerInterface`interface. This means that the entire logging system can easily be replaced by other implementations, such as the popular Monolog library.

Integration Tests and Data Integrity

Testing controllers has always been problematic. While ControllerTestCase solved some of the problems, we identified this class as a source of problems and confusion among our users. We decided to implement the new IntegrationTestCase class as a way totest all aspects of an HTTP request in your application without much mocking being involved. This should help you improve code quality and ensure that your application and routes are working as expected.

We also made the fixtures system better, allowing developers to define and work with foreign key constraints in their database. The fixtures system will now correctly load all data and enable constraints right before your test code is executed.

New Bake templates

With the date for a stable release getting closer and closer we decided to give a new look to default baked applications. Hopefully the new look will feel fresher, more modern, and easier to work with.

Separate packages

We’ve seen an increasing interest in using the new ORM outside the framework or within older CakePHP applications. One of our goals since the start has been making this possible. We have already begun the work to split the framework into various standalone components that can be reused and installed with composer. While the ORM has not yet been extracted into its own repository, most of the necessary pre- requisites are complete. As a product of this work, we have already extracted several components out of the main code base:

  • Collections: Provides a set of tools to manipulate arrays or Traversable objects in an efficient and elegant way.
  • Validation: The excellent and flexible validation library can now be used in any project!
  • Utility: Provides the Hash, Inflector, String and Xml classes.
  • Event: Our Signal-Slot (or Observer Pattern) implementation.
  • Core: The CakePHP core, containing the Configuration and Plugin management classes.

It is important to note that the these repositories are read-only, development will continue in the main CakePHP repository and code will be synchronized regularly to these splits. Please open any ticket or pull request directly in the main github repository.

ORM Related Improvements

  • Added Query::autoFields(). This controls whether the fields for the main table are automatically selected.
  • Ability to pass finder options to custom finders from the paginator by using the finderOptions key.
  • It is now possible to get the default column values out of the database using the SchemaTable::defaultValue().
  • Added accessibleFields as an option key for newEntity() and patchEntity(). This will allow finer grain control for mass- assignment.
  • TranslateBehavior automatically finds translations based on the current application locale.
  • Table::findOrCreate() was added.
  • Ability to override the join type for an association using contain()

Plugin Shells

Shells in plugins can now be called without prefixing with the plugin name. For example for a do_stuff shell living in the Tools plugin, you can execute:

 `
bin/cakedo_stuff

`

Other improvements

  • New uploadedFile validation rule.
  • Made String::uuid() 3 times faster.
  • Better exception reporting on fatal errors.
  • Inflector was optimized for better performance.
  • Several optimizations in the Hash class.
  • Added Collection::buffered() to transform non-rewindable iterators in rewindable ones.

Community Plugins

More plugins for version 3.0 are starting to pop. Here’s a list of what we found interesting:

  • TwigView Use Twig as the default templating engine.
  • Imagine Image manipulation plugin
  • Geo Contains utility libraries and behaviors for working with geo data.
  • Blame Records the user id who modified a row in the database.
  • CakePdf Generates PDF files using different engines
  • Authenticate Authorization and Authentication adapters
  • TinyAuth A lightweight authorization system.
  • TwitterBootstrap A plugin to generate Boostraped interfaces
  • Whoops Replaces the default exception renderer with a nice debugging interface.
  • Assetic Minifies and pre-processes CSS and Javascript We’d like to thank again everyone who has contributed thoughts, code, documentation or feedback to 3.0 so far.

Download the release

You can grab the packaged release here: cakephp-3-0-0-beta2.zip

published on Sep 28, 2014 12:00 AM

Read more

CakePHP 2.5.4 released

CakePHP 2.5.4 released

The CakePHP core team is proud to announce the immediate availability of CakePHP 2.5.4.

The CakePHP core team is proud to announce the immediate availability of CakePHP 2.5.4. 2.5.4 is a bugfix release for the 2.5 release branch. A short list of the changes you can expect is:

  • Improved SMTP auth reply checks.
  • Headers are now correctly sent when using ajaxLogin elements with AuthComponent.
  • Errors in sample schema files were corrected.
  • SecurityComponent no longer puts URLs containing a space into the blackhole callback.
  • Year validation now accepts dates from 1800 and later.
  • RequestHandlerComponent will unserialize request bodies on DELETE requests.
  • Transactions are now rolled back in saveAssociated/saveMany when exceptions are raised.
  • Model::afterFind() is no longer called twice for hasOne/belongsTo associations. It is now only called once, with the model alias format.
  • Join building now accepts no conditions. When joins are created with no conditions a cross will be created unless where conditions correctly restrict the query.
  • SchemaShell now correctly handles the –file and –name switches.
  • Generated schema files have more predictable names now. Instead of using the APP_DIR value, they will always used ‘App’ for application schema files.
  • Exceptions arising from race conditions in FileEngine are now ignored.
  • CakeTime now returns ‘’ on invalid input.
  • Translation functions correctly format placeholders when the first value is null.
  • CURRENT_TIMESTAMP is no longer used as a string default value for TIMESTAMP columns with UPDATE CURRENT_TIMESTAMP in MySQL.
  • Words ending in ‘data’ are no longer inflected to datum. This means works like ‘FileMetadata’ are not inflected incorrectly.

You can view the full changelog on cakephp.org. I’d like to thank the people who have contributed to this release. Your bug tickets, documentation edits, and patches/pull requests are a big part of what keeps CakePHP alive and ticking. Download a packaged release on github.

published on Sep 2, 2014 12:00 AM

Read more

CakePHP 3.0.0-beta1 released

CakePHP 3.0.0-beta1 released

The CakePHP core team is excited to announce the first beta release of CakePHP 3.0.0.

The CakePHP core team is excited to announce the first beta release of CakePHP 3.0.0. In the weeks since 3.0.0-alpha2, we’ve been hard at work incorporating community feedback on the new release, and completing the remaining changes that will break compatibility in a significant way.

Breaking Changes since 3.0.0-alpha2

Since the release of 3.0.0-alpha2 there have been several changes that will break compatibility with existing applications.

I18n has been re-implemented

Built on top of ext/intl and Aura/Intl the new localization subsystem offers more powerful replacement syntax, and retains a backwards compatible sprintf() based formatter. Consult the new i18n documentation for more information. The L10n class has been removed.

NumberHelper uses intl now

The Number library and NumberHelper now use intl internally for formatting currencies and values. This makes NumberHelper completely aware of the application’s current locale. The addFormat() method has been removed.

Directory layout changes

More changes to the directory layout of a CakePHP application have been made:

  • src/Config is now /config.
  • src/bootstrap.php is now /config/bootstrap.php.
  • Log files are now in a top level directory by default. Having them mixed in with other actually temporary data sometimes resulted in people accidentally deleting their log files.
  • Bake templates should now be put in src/Template/Bake.

Vendor Prefixed Plugins Have Changed

Plugins that use vendor prefixes e.g: (AcmeCorpUsers) are no longer renamed. Instead of using Users.User, you must now use AcmeCorp/Users.User. Additionally the vendor prefix will be used as folder name in the plugins folder, so the plugin will be installed in plugins/AcmeCorp/Users folder.

Methods removed

  • Many of the infrequently used methods defined in basics.php have been removed. Functions like config() no longer exist.
  • Validation::ssn() has been removed.
  • Support for CASE statements has been added to the ORM.
  • Helper::webroot(), Helper::assetUrl(), Helper::assetTimestamp() have been moved to a UrlHelper. This allows you to easily replace the URL building features in each of your helpers. You will need to add Url to the $helpers list in your helpers.
  • App::objects() has been removed.

We hope to minimize the impact of breaking changes in future beta and release candidate releases.

New features in 3.0.0-beta1
  • Improved error pages for plugins.
  • Numerous bugs have been fixed in the ORM and across the framework.
  • Cookie paths are now set to the application’s base directory by default.
  • Query objects can be json serialized now.
  • Shell::param() was added.
  • Added a new collection() global shorthand function to convert arrays to collections.
  • Many API documentation blocks and book sections have been improved.
  • Multiple optimizations for performance.

For more details on all the changes in 3.0.0, you can consult the migration guide. In closing, we’d like to thank all of the people that have helped so far with the 3.0 release. We’ve made great progress and without your help we wouldn’t be here today.

Download a packaged release.

published on Aug 23, 2014 12:00 AM

Read more

CakePHP 3.0.0-alpha2 Released

CakePHP 3.0.0-alpha2 Released

The CakePHP core team is proud to announce the immediate availability of CakePHP 3.0.0-alpha2.

The CakePHP core team is proud to announce the immediate availability of CakePHP 3.0.0-alpha2. CakePHP 3.0.0-alpha2 is the second alpha release for CakePHP 3.0.0. In the month since 3.0.0-alpha1 a few new features have been merged, and many issues have been fixed.

New Features in 3.0.0-alpha2

Router Refactor and Builder Based APIs.

The Router class has been re-factored internally and new methods have been added to allow your routes file to stay DRYer than ever before. In addition to improved methods, the performance of parsing incoming URLs has been greatly improved. Router is stricter about missing routes, and will notify you (via an exception) when a URL cannot be parsed or matched with the connected routes.

The default routes provided by CakePHP have been removed. While helpful in the prototyping stages, these routes created issues with duplicate content and were often not used in larger applications. In their place, a smaller subset of routes is provided to help with the prototype stage of application development. If you have an existing application using 3.0, you will need to update your routes.php file.

CacheHelper Removed

CacheHelper has been removed from CakePHP. The core team feels that the functionality this helper provided is best handled by standalone servers like Varnish. While we explored building a ESI based replacement for CacheHelper, there were a number of edge cases that would have complicated the implementation.

ORM Improvements

  • Empty associations in BelongsTo and HasOne associations no longer hydrate an empty entity. Instead the association property will be ` null`.
  • Options for all the various ORM operations are now consistent.
  • You can specify a white list of fields when marshaling data out of the request and into entities.
  • It is now easier to implement custom column types with the ` _initializeSchema` table hook method.
  • Query::newExpr() now accepts a SQL expression.
  • Conditions with nullable values are easier to build ` ‘fieldIS’=>$val` will generate correct SQL when ` $val` is not ` NULL`.
  • Conditions with ` IN` clauses work better with empty data.

Other Changes

  • HtmlHelper and FormHelper had their ` $confirmMessage` arguments removed and replaced with ` confirm` options.
  • Improved errors for Cells.
  • Prefixed controllers can now use prefixed layouts which will be checked automatically.
  • Cookies are now read and decrypted lazily.
  • The ` ssl` routing option is now ` _ssl`.
  • The ` [method]` routing option is now ` _method`.
  • Header based route matching has been removed. It was very infrequently used.
  • Router::resourceMap() has been removed. New options for Router::mapResources() replace the need to have this method.
  • Bcrypt hashing has been removed from ` Security::hash()`

There are still tickets available for CakeFest 2014. You can get your tickets now to join us in Madrid for exciting talks and tutorials on CakePHP and related technologies.

For more details on all the changes in 3.0.0, you can consult the migration guide. I’d like to thank everyone who has contributed thoughts, code, documentation or feedback to 3.0 so far. We are very grateful for all the early adopters and their feedback. Getting issues found and fixed early is a huge help.

published on Jul 28, 2014 12:00 AM

Read more

CakePHP 2.5.3 and 1.3.20 released

CakePHP 2.5.3 and 1.3.20 released

The CakePHP core team is proud to announce the immediate availability of CakePHP 2.5.3 and CakePHP 1.3.20.

The CakePHP core team is proud to announce the immediate availability of CakePHP 2.5.3 and CakePHP 1.3.20. CakePHP 2.5.3 is a bugfix release for the 2.5.x release branch. 1.3.20 is a bugfix release for 1.3.x. The 1.3.20 release contains an important fix to address a potential race condition in Model::save() that can cause data loss when records are deleted during concurrent updates. The same fix is included in 2.5.3.

A short list of the changes you can expect in 2.5.3 are:

  • TextHelper::autoLinkEmail() now links email addresses adjacent to HTML elements.
  • ‘research’ is now pluralized by Inflector properly now.
  • ‘stadium’ is now pluralized by Inflector properly now.
  • The schema included for the ACL tables now includes indexes to help improve performance.
  • APCEngine cache is now compatible with APCu.
  • App::pluginPath() is deprecated. You should use Plugin::path() instead.
  • API doc blocks have been improved in many classes.
  • Email validation rules in CakeEmail have been relaxed. Both email addresses with UTF-8 characters and IDN domain names are generally deliverable but were failing filter_var().
  • CakeResponse::sharable() now sets the public max-age header.
  • Model::getDataSource() now correctly switches the schemaName property. This fixes a regression introduced in 2.4.8.
  • Validation::inList() no longer accepts hexadecimal values for numeric checks.
  • Multi use CSRF tokens now have their expiration updated on each request.
  • h() now performs better.
  • Missing fixture errors have been improved.

If you missed out on the early-bird tickets for for CakeFest 2014, there are still tickets available and the conference schedule.

We’d like to thank Kurita Takashi for his on-going help in identifying possible security issues in CakePHP. You can view the full 2.5.3 changelog and 1.3.20 changelog on cakephp.org. I’d like to thank the people who have contributed to this release. Your bug tickets, documentation edits, and patches/pull requests are a big part of what keeps CakePHP alive and ticking.

You can download packaged releases on github.

published on Jul 21, 2014 12:00 AM

Read more

CakePHP 3.0.0-alpha1 released

CakePHP 3.0.0-alpha1 released

We are excited to announce one new release in the 3.x series, approaching now a stable release

The CakePHP core team proudly announces the first alpha release of CakePHP 3.0.0. In the months between 3.0.0-dev3 and this release, we’ve been working really hard at getting more of the remaining parts implemented, and incorporating all the great feedback we’ve gotten from the community so far.

There are still a few larger features to be completed before we go to a beta release, most importantly:

  • Updated i18n and L10n features.
  • A replacement for CacheHelper based on Edge Side Includes.
  • A new routing API for simpler and faster route declaration.

The alpha releases will focus on getting these key features completed. After which, we’ll start beta releases focusing on polishing up any rough or confusing features, improving error messages/help and porting over plugins produced by the core team.

We’ve been truly humbled by the fantastic feedback and support we’ve received from the community in the last month. We’ve had numerous bug reports, pull requests and documentation edits that have helped improve 3.0 overall.

This release also comes with complete documentation for the new features and changes, make sure you check out the new CakePHP 3.0 book to read about them in detail.

Below is the list of new features and changes that made it into 3.0.0-alpha1:

Reworked Dispatcher Filters

Dispatcher filters have been reworked and expanded to include some of the previously ‘magic’ features of CakePHP. Filters are now registered as instances instead of through configuration data making it simple to do dependency injection.

Dispatcher filters also include a way to restrict when they are applied to any given request.

New Session Object

Session management has always been a static class in CakePHP which has proven to be problematic in a number of ways. For CakePHP 3.0, you can access the session from the request object ` $this->request->session()`.

This change also makes the session easier to test, and allows CakePHP to use PHPUnit 4.x

FlashHelper and FlashComponent

Flash messages play an important part in modern web applications. While CakePHP has always had rudimentary flash messaging support, CakePHP 3.0 gives developers even more tools to create and render multiple kinds of messages in a simple way. To make this happen a separate component and helper were created. We’d like to thank jadb and bcrowe for making this code happen.

CookieComponent

CookieComponent has only been able to manage one cookie namespace at a time in the past. While it offered powerful tools for creating encrypted cookies, those tools were hard to use consistently and correctly. The redesigned CookieComponent makes it much easier to separate the configuration of cookie namespaces and the handling of cookie data.

Passwords Default to Bcrypt

Using bcrypt for passwords is a current best-practice. To help steer developers in the right direction, we’ve made bcrypt the default password hashing system in CakePHP, and provided an easy to use FallbackHasher that will allow you to incrementally update your password hashes from older hashing algorithms.

Themes and Plugins Merged

For CakePHP 3.0.0, we wanted to make themes more powerful and more robust. As we looked at ways of improving themes, we realized that what we really wanted were plugins. To that end, you can now use any plugin as a theme. This makes packaging and re-distributing themes easy as they are simply plugins do and can include helpers and cells.

App and Plugins share a standard suggested directory layout

To make your experience developing as consistent as possible, we’ve updated both the application skeleton and plugin skeletons to use the same directory structure. This will help make working with plugins feel just like you’re working in a small modular application.

ORM Improvements

Several API changes made their way into the new ORM. Now it is simpler to specify deep associations for saving operations and we have changed a couple conventions to reduce the learning curve and confusion among new adopters.

Better Performance

We’ve taken an initial performance review over the new features in 3.0, and spent some time removing obvious bottlenecks. We’re happy to announce that we succeeded at making the bootstrap process and several parts of the helpers template generation faster.

Additionally, we’ve identified a way to make the routing process several times faster. We’ll be implementing these new ideas for the following beta release.

You can download the release or just use composer create-project -s dev cakephp/app to start using CakePHP 3.0 today!

published on Jun 25, 2014 12:00 AM

Read more

CakePHP 2.5.2 and 1.3.19 released

CakePHP 2.5.2 and 1.3.19 released

The CakePHP core team is proud to announce the immediate availability of CakePHP 2.5.2 and CakePHP 1.3.19.

The CakePHP core team is proud to announce the immediate availability of CakePHP 2.5.2 and CakePHP 1.3.19. CakePHP 2.5.2 is a bugfix release for the 2.5.x release branch. 1.3.19 is a bugfix release for 1.3.x. The 1.3.18 release contained a regression related to the form tampering security fix that 1.3.19 resolves.

A short list of the changes you can expect in 2.5.2 are:

  • cake console command now works when CDPATH is used.
  • Inflection of ‘feedback’ is now correct.
  • Incorrect status line parsing in HttpSocketResponse has been fixed.
  • Form tampering protection has been fixed when form URL’s contain multiple query string parameters.
  • Creating disabled select options no longer disables the select element when array(1) is used for the disabled option.
  • Trailing star routes can now be reverse routed.
  • Older blowfish hashes are now accepted, and can be used with AuthComponent.
  • A username of ‘0’ can now be used with AuthComponent.
  • Improved API docs.
  • Hash::extract() now allows [prop=1] to match boolean true.

If you haven’t already purchased your ticket for CakeFest 2014 the conference schedule has been announced and this year is shaping up to be another fantastic installment in the CakeFest tradition.

You can view the full 2.5.2 changelog and 1.3.19 changelog on cakephp.org. I’d like to thank the people who have contributed to this release. Your bug tickets, documentation edits, and patches/pull requests are a big part of what keeps CakePHP alive and ticking.

You can download packaged releases on github

published on Jun 15, 2014 12:00 AM

Read more

CakePHP 2.4.10 and 2.5.1 released

CakePHP 2.4.10 and 2.5.1 released

The CakePHP core team is proud to announce the immediate availability of CakePHP 2.4.10 and 2.5.1.

The CakePHP core team is proud to announce the immediate availability of CakePHP 2.4.10 and 2.5.1. 2.4.10 is the final bugfix release for the 2.4 release series. Going forward, 2.4 will only receive security releases. 2.5.1 is a bugfix release for the 2.5 release branch. A short list of the changes you can expect in 2.4.10 is:

  • Controller::referer() behaves correctly when local URLs are generated.
  • TextHelper::tail() was restored.
  • FormHelper security tokens only use the path and query parts of a URL to generate hashes. This fixes problems when absolute URL’s were used to create forms.
  • Missing component error pages have correct paths now.
  • Compatibility with PHP5.6 was improved. 2.5.1 contains the following changes:
  • Loading data from models and their associations with multiple datasources works properly now. This fixes a regression added in 2.5.0-beta.
  • FormHelper::postLink() had a backwards incompatible signature change in 2.5.0-dev. This method is now backwards compatible.
  • CakeEmail now uses the correct mimetype for emails that contain text & html but no attachments. Previously, multipart/mixed was used which caused some clients to incorrectly handle email messages.
  • The test harness will now locate PHPUnit installed through composer.

If you haven’t already purchased your ticket for CakeFest 2014 the conference schedule has recently been announced and this year is shaping up to be another fantastic installment in the CakeFest tradition.

You can view the full 2.4.10 changelog and 2.5.1 changelog on cakephp.org. I’d like to thank the people who have contributed to this release. Your bug tickets, documentation edits, and patches/pull requests are a big part of what keeps CakePHP alive and ticking.

You can download packaged releases on github

published on May 18, 2014 12:00 AM

Read more

CakePHP 2.5.0 Released

CakePHP 2.5.0 Released

The CakePHP core team is proud to announce the immediate availability of CakePHP 2.5.0.

The CakePHP core team is proud to announce the immediate availability of CakePHP 2.5.0. There have been a few changes to 2.5.0 since the RC2 release:

  • FormHelper::postLink() fixes from 2.4.9 have been merged in.
  • Numerous API documentation improvements.
  • TextHelper::tail() was fixed.
  • SQLServer::describe() was failing no longer fails when used with fixtures.
  • Authentication adapters can be aliased allowing you to use the same adapter multiple times with different password hashing strategies.
  • The redis cache engine now supports unix_socket.
  • PaginatorComponent will no longer do a find(‘count’) for the first page when there are fewer records than the current page limit.

You can view the detailed changelogs as well.

New feature highlights

Cache::remember()

This method allows you to implement read-through cache operations. For the passed cached key, it will first look for any cached data that is still valid. If not found, a callback method will be executed and its return value stored under the cache key.

You will find this useful for reducing the amount of repetitive code around checking for cache misses.

Improved Memcached support

A new Cache engine has been added to provide support for the php extension ext/memcached, which is the faster and better supported extension for utilizing this popular key-value database. In introducing this new adapter, we have deprecated the old Memcache engine and plan for its removal in 3.0.

CompletionShell

For shell environments that support command completion such as bash and zsh, we have provided a cake shell that will help you get command and options completion for your cake shells by hitting the tab key. If you have ever wondered what shells are available, or what options they can take, this might be for you. Make sure to check the documentation for more information on how to set this up.

Security::encrypt() and AES encrypted cookies

If for any reason you are storing data in cookies that should not be changed by the user, you can now use AES encrypted cookies. This utilizes the new AES-256 encryption offered by the Security class to prevent various classes of attacks, such as cookie tampering.

Consistent priorities in global and local events

One limitation in previous CakePHP versions was that listeners attached to the global EventManager would always be called before any other local listeners, despite the priorities. CakePHP 2.5 unifies the priority queue between global and local event listeners. With a single unified set of priorities, you can implement more complex and complete aspect oriented programs.

CakePHP 2.5.0 is now marked as stable. 2.5.x is an API compatible upgrade for the 2.x release series. Make sure you read the migration guide as there are a few deprecations you may want to account for. Development has already started on 2.6.0, which will be another API compatible release for the 2.x release series.

A huge thanks to all involved in terms of both contributions through commits, tickets, documentation edits, and those whom have otherwise contributed to the framework. As an entirely community powered project CakePHP relies on your contributions to continue.

published on May 13, 2014 12:00 AM

Read more

CakePHP 3.0.0-dev3 released

CakePHP 3.0.0-dev3 released

Fresh slices of the new development preview for version 3.0 are hot and out of the oven!

The CakePHP core team proudly announces the third development preview of CakePHP 3.0.0. In the couple months between 3.0.0-dev2 and this release, we’ve been working really hard at getting the remaining big parts of the new features we wanted to introduce into the framework.

We have decided to not do a future 3.0.0-dev4 release as everything that was planned for it was already completed. This means that the next release will be ‘alpha’ and the team will focus mostly on polishing the current features, documentation and porting some of the 2.x plugins. We’re really happy with the progress we have made and the pace at which 3.0 is going.

Additionally the team has spent plenty of time incorporating all the community feedback into the new ORM and we’re humbled by the amount of people putting some of their time into making it even more comprehensive and easy to use.

This release also comes with full documentation for the new features and changes, make sure you check out the new CakePHP 3.0 book To read about them in detail.

Below the list of new features and changes that made it into 3.0.0-dev3:

Console improvements

  • New ConsoleIO class added. It is a convenience class containing common method for input/output in shells.
  • Console methods will receive passed arguments as function parameters, much like controller actions.
  • Adding subcommands for Tasks is now required.
  • Possibility to alias any shell command, for example instead of ` Console/cakebakemodel` you could do ` Console/cakebmodel`.

View Cells

View cells are small classes that offer controller-like functionality but can be used directly in the view to pull data from any source and render certain template. Read more about View Cells

New Time Library

The Time class was completely re-implemented to internally use Carbon. Whatever the Carbon library and ` DateTime` can do, the new Time lib can too. This means that the method in ` Time` are no longer static, you need and instance of the object to get access to its methods.

In addition to the new Time class being added, it has been integrated with the ORM, meaning that any timestamp/datetime columns in your entities will be able to leverage the power CakeUtilityTime provides.

Lastly, the Time lib uses the ` intl` php extension to provide reliable locale-aware date formatting which is several times superior to the support that we could offer in the 2.x series.

Read more about Time

Bake

Bake is finally working again in CakePHP 3.0, but it also brings a nice number of great new features:

  • Bake is now pluggable! You can create your own bake tasks and they will be automatically discovered. This means that you can now implement your own ` Console/cakebakesuper_table`
  • Ability to bake shells, cells, components, behaviors and more

Additionally we added some other changes:

  • Microsoft SQL Server support was added to the new ORM
  • TreeBehavior was re-implemented and offers feature parity with its previous version form 2.x
  • Both Behaviors and Components have now a ` config()` method, configuration using public properties was removed
  • Multiple bugfixes in the ORM
  • ` Collection::nest()` and ` Collection::listNested()` were added for dealing with hirarchical data
  • ` Validator::notEmpty()` was added as a complement to ` Validator::allowEmpty()`
  • Moved exception files to their corresponding namespaces
  • Simplified View objects construction, they are not dependent on controllers anymore
  • ` Request::isMobile` now uses an external library to correctly match the ever-growing number of mobile devices

Community plugins

Some have been also very busy catching up with the changes introduced daily in the 3.0 branch. We’d like to mention the CRUD plugin which contains a dynamic scaffolding and automatic Admin generator. It may be a great way of getting on into CakePHP 3.0 the fast way.

Dereuromark’s Tools plugin seems to be having some interesting activity with some good behaviors ready to use in CakePHP 3.0.

Up next

Our next release will be marked as alpha and we are going to focus on the following:

  • Make the session object live inside the Request object. It will not be static anymore
  • Implementing the new middleware layer
  • Themes implemented as plugins
  • CookieComponent reworked.
  • Overhaul i18n to use intl and add support for i18n engines

We’d like to thank everyone who has contributed thoughts, code, documentation or feedback to 3.0 so far. It looks like it is going to be the single most important and feature rich release when it is marked stable!

published on May 6, 2014 12:00 AM

Read more

CakePHP 2.4.9 released

CakePHP 2.4.9 released

The CakePHP core team is happy to announce the immediate availability of 2.4.9[1]. This releases contain a bug fix related to the security fix in 2.4.8.

The CakePHP core team is happy to announce the immediate availability of 2.4.9[1]. This releases contain a bug fix related to the security fix in 2.4.8. A short list of changes you can expect in 2.4.9 are:

  • FormHelper::postLink() now works correctly with SecurityComponent. In 2.4.8 a mistake was made that resulted in incorrect hashes being generated.

If you use postLink() and have upgraded to 2.4.8 it is recommended that you upgrade to 2.4.9 to avoid any potential issues. You can download a packaged release from github[2].

Links

published on Apr 30, 2014 12:00 AM

Read more

CakePHP 1.3.18 and 2.4.8 released

CakePHP 1.3.18 and 2.4.8 released

The CakePHP core team is happy to announce the immediate availability of 1.3.18 and 2.4.8. These releases contain security fixes and are recommended for all CakePHP developers using SecurityComponent.

The CakePHP core team is happy to announce the immediate availability of 1.3.18[1] and 2.4.8[2]. These releases contain security fixes and are recommended for all CakePHP developers using SecurityComponent. A short list of changes you can expect in 2.4.8 are:

  • SQLServer now properly appends the schema name when describing tables.
  • Hash::extract() can now match boolean attributes.
  • fclose() errors when using shells should no longer happen.
  • CakeResponse::file() now throws an exception when paths contain ‘..’.
  • ShellDispatcher now casts argv to an array. This fixes issues when cake console was invoked from a non-cli SAPI.
  • TextHelper::autoLink() now correctly links urls with subdomains containing ‘_’.
  • SecurityComponent form tampering hashes now include the URL including the query string as a hash input.

A short list of changes you can expect in 1.3.18 are:

  • Model conditions containing : or ? are now handled correctly. This fixes issues around using casting in conditions
  • SecurityComponent form tampering hashes now include the URL path as a hash input.

As previously mentioned, a security issue related to the SecurityComponent was fixed. These releases are recommended upgrades for anyone using SecurityComponent. Prior to these relases, forms secured by SecurityComponent could be submitted to any action without triggering SecurityComponent’s tampering protection. If an application contains multiple POST forms to manipulate the same models, it could be vulnerable to mass assignment issues. Thanks to Kurita Takashi for notifying the CakePHP team of this issue, and suggesting a fix.

A huge thanks to all involved in terms of both contributions through commits, tickets, documentation edits, and those whom have otherwise contributed to the framework. Without you there would be no CakePHP.

Links

published on Apr 29, 2014 12:00 AM

Read more

CakePHP 2.5.0-RC2 Released

CakePHP 2.5.0-RC2 Released

The CakePHP core team is proud to announce the immediate availability of CakePHP 2.5.0-RC2

The CakePHP core team is proud to announce the immediate availability of CakePHP 2.5.0-RC2[1]. This is the second release candidate for the 2.5.0 branch. 2.5.0-RC2 contains bugfixes and a few new features added since 2.5.0-RC1 was released. When complete, 2.5.0 will replace the 2.4.x branch. A migration guide is available in the book [2] and we encourage you to read it if you are upgrading from an older version.

Changes since 2.5.0-RC1:

  • AssetDispatcher early 404’s were reverted. They caused problems with extension based routing in plugins.
  • View paths for plugins are now cached. This change optimizes lookup times when using multiple views/elements from a plugin.
  • CakeEmail configuration can now set the layout without setting the template.
  • Transliteration rules used by Inflector::slug() have been expanded.
  • CakeResponse::file() now rejects paths with ..

If there are no important issues found, a stable release of 2.5.0 should be released in the next few weeks.

A huge thanks to all involved in terms of both contributions through commits, tickets, documentation edits, and those whom have otherwise contributed to the framework.

Links

published on Apr 27, 2014 12:00 AM

Read more

CakePHP 2.5.0-RC1 Released

CakePHP 2.5.0-RC1 Released

The CakePHP core team is proud to announce the immediate availability of CakePHP 2.5.0-RC1.

The CakePHP core team is proud to announce the immediate availability of CakePHP 2.5.0-RC1[1]. This is the first release candidate for the 2.5.0 branch. The 2.5.0-RC contains bugfixes and a few new features added since 2.5.0-beta was released. When complete, 2.5.0 will replace the 2.4.x branch. A migration guide is available in the book [2] and we encourage you to read it if you are upgrading from an older version.

Changes since 2.5.0-beta

  • HtmlHelper::addCrumb() can now be chained to add multiple crumbs.
  • BaseAuthorize::mapActions() can now map custom action types.
  • cake acl delete now deletes all matching rows.
  • Dispatcher::_invoke() no longer takes a response parameter.
  • Set class is now deprecated and has been removed in 3.0. You should use Hash class instead.
  • CakePlugin::loadAll() now merges settings with defaults.
  • AssetDispatcher now returns 404 errors with no content body when plugin/theme assets cannot be found.

If there are no important issues found, a stable release of 2.5.0 should be released in the next few weeks.

A huge thanks to all involved in terms of both contributions through commits, tickets, documentation edits, and those whom have otherwise contributed to the framework.

Links

published on Apr 11, 2014 12:00 AM

Read more

CakePHP 2.4.7 Released

CakePHP 2.4.7 Released

The CakePHP core team is proud to announce the immediate availability of CakePHP 2.4.7

The CakePHP core team is proud to announce the immediate availability of CakePHP 2.4.7. 2.4.7 is a bugfix release for the 2.4 release branch. A short list of the changes you can expect is:

  • Core fixtures are now included in PEAR packages.
  • Limburgish locale was added to L10n.
  • MailTransport now includes the last error in the exception raised when mail() fails.
  • HtmlHelper::getCrumbList() supports the escape parameter now.
  • Describing tables in specific SQLserver schemas now works correctly.
  • Improved API docs for several classes.
  • URLs are correctly generated when two routing keys start with the same substring.
  • Model::deleteAll() works correctly when using MySQL views.
  • CakeEmail sets theme on helpers now.
  • Hidden inputs generated in radio(), select() and checkbox() have the ‘form’ attribute set when provided.
  • Inflection for words ending in ‘aves’ was improved.
  • CakeTestCase::assertTags() now runs much faster.
  • CakeTestCase::assertTags() requires all attributes to be verified now.
  • AclShell::delete now removes all matching records.
  • CakeEmail now correctly renders messages when the template and layout are in different plugins.

You can view the full changelog on cakephp.org[1]. I’d like to thank the people who have contributed to this release. Your bug tickets, documentation edits, and patches/pull requests are a big part of what keeps CakePHP alive and ticking. Download a packaged release on github[2].

Links

published on Apr 5, 2014 12:00 AM

Read more

CakePHP 2.5.0-beta Released

CakePHP 2.5.0-beta Released

The CakePHP core team is proud to announce the immediate availability of CakePHP 2.5.0-beta.

The CakePHP core team is proud to announce the immediate availability of CakePHP 2.5.0-beta[1]. This is the first beta release for the 2.5 branch. The 2.5.0-beta release contains several new features that improve CakePHP’s performance, security and ease of use. When done, this new version will replace the 2.4.x branch. A migration guide is provided in the book [2] and we encourage you to read it if you are upgrading from an older version.

New features

While the migration guide[2] contains all the changes in 2.5.0, here are a few we are excited about.

Cache::remember()

This method allows you to implement read-through cache operations. For the passed cached key, it will first look for any cached data that is still valid. If not found, a callback method will be executed and its return value stored under the cache key.

You will find this useful for reducing the amount of repetitive code around checking for cache misses.

Improved Memcached support

A new Cache engine has been added to provide support for the php extension ext/memcached, which is the faster and better supported extension for utilizing this popular key-value database. In introducing this new adapter, we have deprecated the old Memcache engine and plan for its removal in 3.0.

CompletionShell

For shell environments that support command completion such as bash and zsh, we have provided a cake shell that will help you get command and options completion for your cake shells by hitting the tab key. If you have ever wondered what shells are available, or what options they can take, this might be for you. Make sure to check the documentation for more information on how to set this up.

Security::encrypt() and AES encrypted cookies

If for any reason you are storing data in cookies that should not be changed by the user, you can now use AES encrypted cookies. This utilizes the new AES-256 encryption offered by the Security class to prevent various classes of attacks, such as cookie tampering.

Consistent priorities in global and local events

One limitation in previous CakePHP versions was that listeners attached to the global EventManager would always be called before any other local listeners, despite the priorities. CakePHP 2.5 unifies the priority queue between global and local event listeners. With a single unified set of priorities, you can implement more complex and complete aspect oriented programs.

The API docs[3] and cookbook have been updated to reflect the changes and updates for 2.5.0.

The CakePHP core team would also like to welcome Brian Crowe (bcrowe) to the team. Brian has been actively improving the cookbook, API docs and code during the development of 2.5, and 3.0.

A huge thanks to all involved in terms of both contributions through commits, tickets, documentation edits, and those whom have otherwise contributed to the framework.

Links

published on Mar 26, 2014 12:00 AM

Read more

CakePHP 3.0.0 dev preview 2 released

CakePHP 3.0.0 dev preview 2 released

The CakePHP core team is very excited to announce the second development preview of CakePHP 3.0

The CakePHP core team is excited to announce the second development preview of CakePHP 3.0.0[1]. In the few months since 3.0.0-dev1, we’ve been hard at work incorporating community feedback on the ORM, and building out some of the functionality that was missing in the first development preview.

New features in 3.0.0-dev2

  • CakePHP has adopted the PSR-4 autoloader standard. If you are updating, make sure you update composer as well using ` composerself- update`.
  • The directory structure of both CakePHP and the App skeleton has been simplified a bit thanks to PSR-4.
  • The AclComponent has been removed - It will be returning as a plugin.
  • The TestShell, and webrunner have been removed in favor of only supporting phpunit from the CLI, and VisualPHPUnit.
  • View templates have been moved from View/ to Template/. This was done so the View/ directory would only contain view classes and helpers.
  • The HtmlHelper, FormHelper, and SessionHelper use string templates consistently.
  • ID attributes are now always generated with ` -` instead of CamelCase. This was done to standardize on one convention for CSS selectors.
  • API documentation and the cookbook have had many new sections and improvements.
  • Scaffold has been removed. Improved dynamic scaffolding is now available through the CRUD plugin[2] which is already compatible with 3.0 and takes away much of the repetitive tasks done in controllers.
  • The UpgradeShell has been moved into a separate plugin.
  • Better debugging output for some complex objects like Entities, Tables and Queries. Also added a special method to control what data is outputed for objects when using the debug() function
  • Added Collection::insert()

FormHelper

FormHelper has been re-built from the ground up. It features a new extensible widget system. Form widgets allow you to build self contained input widgets. This makes it easy to define complex widgets like the datetime widget in application or plugin code. Once created, widgets can be combined with other FormHelper features like ` input()`.

FormHelper also works with the new ORM now. You can create forms for individual entities, or collections of entities:

 `
//Createaformforasingleentity&itsassociations
echo$this->Form->create($article);

//Createaformformultipleentities&theirassociations.
echo$this->Form->create($articles);

`

FormHelper also features a pluggable context system that allows you to integrate FormHelper with any ORM you may wish to use.

TranslateBehavior

TranslateBehavior has been re-built from the ground up. It features the long awaited ability to translate all models including associations from a find(). The new ` TranslateTrait` makes dealing with multiple translations in your entities simple as well.

ORM improvements

We’ve continued to build out capabilities in the ORM. Some notable improvements in dev2 were:

  • Composite primary key support - The ORM now supports composite primary keys in all associations.
  • The Model.beforefind event is now triggered for all associations in the same query.
  • Eager loading is now separate from the Query class. This makes implementing custom eager loading much easier.
  • Model/Repository was renamed to Model/Table. Several people found ‘Repository’ to be a confusing and alien term.
  • Interfaces have been extracted to reduce the reliance on concrete implementations.
  • The formatResults() method has been added to provide many of the features that afterFind() used to do.
  • Query::counter() was added to provide support for complex count logic. This makes it easier to override the count in the PaginatorComponent.
  • Table::patchEntity() was added, it enables you to merge requet form data into an existing entity and its associations.

Up next

Our next release will be yet another development preview. In the dev3 release we are going to focus on updating:

  • Bake and all the related tasks need to be updated to work with the new ORM.
  • Update the i18n extract task to extract validation messages from Table objects
  • Add support for SQLServer. With the database layer reasonably stable adding SQLServer will help developers on windows.

For more details on all the changes in 3.0.0, you can consult the migration guide[2]. I’d like to thank everyone who has contributed thoughts, code, documentation or feedback to 3.0 so far. It’s going to be a major milestone for the project, and we’re just getting started with making it the best version of CakePHP ever.

Links

published on Mar 12, 2014 12:00 AM

Read more

CakePHP 2.4.6 Released

CakePHP 2.4.6 Released

The CakePHP core team is proud to announce the immediate availability of CakePHP 2.4.6. 2.4.6 is a bugfix release for the 2.4 release branch.

The CakePHP core team is proud to announce the immediate availability of CakePHP 2.4.6. 2.4.6 is a bugfix release for the 2.4 release branch. A short list of the changes you can expect is:

  • Extract task handles quotes inside validation messages correctly.
  • Model::field() now works with fields translated with TranslateBehavior.
  • Core tests are no longer part of PEAR packages. This solves issues when the pear package is used as a composer dependency, and an incorrect classmap was generated.
  • FormHelper::checkbox() can now generate checkboxes for empty values.
  • Postgres can now convert boolean fields to integer when using SchemaShell.
  • Changes to how ID’s are generated for radio inputs were reverted. These changes caused issues in some applications.
  • API documentation has been improved.
  • Reverse routing for prefixed actions was improved.
  • Temporary associations setup with TranslateBehavior::bindTranslation() are now correctly unbound & restored.
  • Clearing data with MemcacheEngine will now work with greater than 100 slabs.
  • Validation::decimal() now works with localized floats.
  • Invalid data in datetime pickers is now correctly handled.
  • FormHelper::postLink() and FormHelper::postButton() now handle N dimensional data.

You can view the full changelog on cakephp.org[1]. I’d like to thank the people who have contributed to this release. Your bug tickets, documentation edits, and patches/pull requests are a big part of what keeps CakePHP alive and ticking. Download a packaged release on github[2].

Links

published on Mar 2, 2014 12:00 AM

Read more

Scaffold on Bootstrap 3

Scaffold on Bootstrap 3

My samples in the scaffold design using Bootstrap 3 Nice Scaffolding for CakePHP github.com/xv1t/cakephp-scaffold-bootstrap3 Required: Bootstrap 3 (Testing on 3.1.1) Please see the screenshots: index, view, form

published on Feb 19, 2014 12:00 AM

Read more

CakeFest 2014: Madrid, Spain

CakeFest 2014: Madrid, Spain

Join us at CakeFest 2014, the annual CakePHP conference, held this year in Madrid, Spain, from the 21st until the 24th of August, and experience the very best of open source! Visit http://cakefest.org for info and tickets.

The big 3.0

This year we’re celebrating 9 years of CakePHP, and we want to do it with all of you, our awesome community. There’s also a very important milestone on the horizon, in the form of the lucky number “3”. You really cannot miss this year’s event, held in the beautiful European city of Madrid, Spain, from Thursday the 21st until Sunday the 24th of August.

See more details on the location at http://cakefest.org/location.

We’ve also got an incredible offer for you this year, as we’re providing some tickets which include a room plus breakfast in the 4* hotel that’s hosting the conference! That’s right, all you need is to get there and we’ll take care of the rest. Who said we don’t love you guys?!

Get your tickets now at http://cakefest.org/tickets.

Workshops

The 2 day workshops at CakeFest are an ideal opportunity to learn the internals of CakePHP, and a great way to get up to speed with the latest version of the framework. We’ll be focusing part of the workshops on the new 3.0 code base, helping people get to grips with the new features for this third major revision of CakePHP. Attendees will also receive a personal certificate of attendance from the Cake Software Foundation.

Conference

The conference covers 2 jam packed days of keynotes, presentations, discussions and talks on CakePHP and related technologies, plus an array of activities, such as lightning talks, core team Q, the Hour of Contribution and a raffle. It’s a great time to engage and network with the community, learn from other experienced developers, and party with the core team. Plus, there will be cake!

Call for Papers

Would you like to be a speaker at a conference which draws an international crowd who love PHP and all things cake related? Never spoken before, or don’t think you have anything interesting to share? The annual CakePHP conference draws an exceptionally friendly community of developers, tech lovers and geeks in general. If you’re interested in giving a talk this year, then CakeFest is the ideal event. The submissions are open until April 30th! Just head over to http://cakefest.org and submit your talk proposals. We’re open to anyone for submissions. All it takes is a interesting idea, and we’d love to hear yours!

Sponsorship

Are you working for a company or own a business that would benefit from the unique exposure that comes from sponsoring the annual CakePHP conference? Consult our sponsorship prospectus for more details as well as the sponsor packages currently available.

published on Feb 18, 2014 12:00 AM

Read more

CakePHP 2.4.5 Released

CakePHP 2.4.5 Released

The CakePHP core team is proud to announce the immediate availability of CakePHP 2.4.5

The CakePHP core team is proud to announce the immediate availability of CakePHP 2.4.5. 2.4.5 is a bugfix release for the 2.4 release branch. A short list of the changes you can expect is:

  • Generated DOM ids for radios and checkboxes should now be collision free when using non-alphanumeric values.
  • The postgres driver now quotes schema names. This solves issues with legacy schemas using special characters.
  • Translate behavior now correctly handles translated values of ‘0’.
  • Controller baking now provides better feedback when no controllers are generated.
  • Datetime inputs will not select year 0 when the selected value is ‘0000-00-00’. This improves compatibility with MySQL.
  • Schema creation with the connection parameter now works as expected.
  • URLs are no longer double URL decoded. This fixes lost data when named parameters or path segments contain values that look like URL encoded data.
  • Model::updateCounterCache() no longer triggers a notice error when $this->data is empty.

You can view the full changelog on cakephp.org[1]. I’d like to thank the people who have contributed to this release. Your bug tickets, documentation edits, and patches/pull requests are a big part of what keeps CakePHP alive and ticking. Download a packaged release on github[2].

Links

published on Jan 26, 2014 12:00 AM

Read more

Qimage Component (Image Manipulation Component Cake 2.x)

Qimage Component (Image Manipulation Component Cake 2.x)

Quick Image Component (Qimage) is a component for CakePHP to facilitate image upload and manipulation.

Methods

copy -> Copy uploaded images.

resize -> Resize an image.

watermark -> Add watermark in an image.

crop -> Crop an image.

getErrors -> Get all errors that occurred in Qimage.

More details can be found in the comments of the methods.

See more in Github.

published on Jan 23, 2014 12:00 AM

Read more

An ElasticSearch powered Search Index - your data stays in default

An ElasticSearch powered Search Index - your data stays in default

Use ElasticSearch for your searches, but keep your data in MySQL/Postgres (your default DB config). This behavior saves an “index” string to ElasticSearch for each record afterSave, and searches happen against that, but your data is exactly as it was before.

Elastic Search Index

https://github.com/zeroasterisk/CakePHP-ElasticSearchIndex

This plugin allow for a very easy search index powered by`ElasticSearch`_ with all kinds of`Lucene`_ powered goodness. (it powers GitHub)

With this, you keep your models on your own normal (default) datasource. All saves and finds and joins and callbacks... normal.

But when you attach this behavior, you now have additional callbacks which gather the data you want to use as a search index... it stores that data to ElasticSearch via it’s own datasource, ` index` as setup via the (above) Elastic plugin.

What you end up with is having you cake and eating it too.

  • Your Model and datasource are unchanged and work as before. ** all your data is still where it has always been ** you can still do joins ** non-search conditions can still work on the normal fields
  • The searchy goodness of ElasticSearch / Lucene is avaialble to you ** The indexed string for each record is a customizable second copy of the data’s text ** It’s avaialble on ElasticSearch for any other usage as well

Now you can search by

  • term: foo
  • multi-term: foobar
  • partials: fo*
  • partials in the front: *oo
  • phrases: “foobar”
  • fuzzy term: ~bars (prefix with ` ~`)
  • ... and more ... (suggestions?)

Note: it is working great, but we could use more ElasticSearch special sauce if you want to help improve it.

Install

Get this plugin into place

 `
git submodule add https://github.com/zeroasterisk/CakePHP-ElasticSearchIndexapp/Plugin/ElasticSearchIndex
#or
git clone https://github.com/zeroasterisk/CakePHP-ElasticSearchIndexapp/Plugin/ElasticSearchIndex

`

And install the`Icing`_ Plugin

 `
gitsubmoduleaddhttps://github.com/AudiologyHoldings/Icingapp/Plugin/Icing
#or
gitclonehttps://github.com/AudiologyHoldings/Icingapp/Plugin/Icing

`

In ` app/Config/bootstrap.php` load the plugin

 `
CakePlugin::load('Icing');
CakePlugin::load('ElasticSearchIndex');

`

Copy the default ` ElasticSearchRequest` configuration into your app and edit it to suit your setup.

 `
cpapp/Plugin/Icing/Config/elastic_search_request.php.defaultapp/Config/elastic_search_request.php

`

Note that there’s a ` default` config and a ` test` config which will override the ` default` config... But only if your tests set the following Configure variable:

 `
Configure::write('inUnitTest',true);

`

Now setup into any Models you want to search / index

In your ` Model` add this behavior

 `
public$actsAs=array(
'ElasticSearchIndex.ElasticSearchIndexable'=>array(),
);

`

And here are the behaviour config options, with default values

 `
public$actsAs=array(
'ElasticSearchIndex.ElasticSearchIndexable'=>array(
//urltotheelasticsearchindexforthismodel/table
'url'=>null,
//extraconfigforElasticSearchRequest(parsedfromURL)
'index'=>null,
//extraconfigforElasticSearchRequest(parsedfromURL,ordefaultedto$Model->useTable)
'table'=>null,
//limitthesearchresultstothismanyresults
'limit'=>200,
//detailsneededtolinktoModel
'foreignKey'=>false,//primaryKeytosaveagainst
//dowebuildtheindexaftersave?(yes...)
'rebuildOnUpdate'=>true,
//whenwebuildtheindex,considerthesefields(ignonredifcustommethodonmodel)
//eg:array('title','name','email','city','state','country'),
//orforall(text/varchar)fields:'*'
'fields'=>'*',
//whenwebuildtheindex,dowefinddatafirst?(iffalse,weonlyhavethedatawhichwassaved)
'queryAfterSave'=>true,
//optionalconfigforHttpSocket(bettertoconfigureElasticSearchRequest)
'request'=>array(),
),
);

`

How to Save Records

It’s automatic, after every save , the behaviour will post that record to the ElasticSearch index.

If you want to manually index any model ` $data` arrays (with the fields from this model), in your ` Model` you can do:

 `
$data=$this->read(null,'1234');
$id=$data[$this->alias][$this->primaryKey];
$success=$this->saveToIndex($id,$data);

`

If you have a simple string, you want to index for a record on your ` Model` then you can use:

 `
$id='1234';
$success=$this->saveIndexDataToIndex($id,'Thisisacustomstring,thiswillbeindexed');

`

Customize the data to save to the Index

You can specify a few methods on your model, which override the basic functionality.

Make this method on your model to get customized data for the indexing. It should return a data array for a single record, similar to a ` find(‘first’)`

 `
$findFirstData=$this->getDataForIndex($id)

`

Make this method on your Model to process a data array into a string for indexing.

It expects to get it’s data array from ` $this->data` not from a passed in argument

It should return a string (the text which will be stored in the index)

 `
$indexText=$this->indexData()

`

Make this method on your Model to clean or post-process the index text. You can replace terms, characters or whatever you like.

 `
$indexText=$this->cleanForIndex($indexText)

`

How to re-index all Records

In any Model you can run ` reIndexAll($conditions)` and it will walk through your data and re-index all of them... it can be really slow...

 `
//thisisreallyslow,butitwillre-indexeverything(create/updateindexes)
$statusString=$this->reIndexAll();
//oryoucanpassinanyconditionsyouliketolimitthescopeofthereIndex
$statusString=$this->reIndexAll(array(
'modified>'=>date('Y-m-d00:00:00',strtotime('-2months')),
));

`

How to Search

The core search method for this behavior is ` searchAndReturnAssociationKeys` which returns just the ` id`s of the ` Model`.

 `
$primaryKeys=$this->searchAndReturnAssociationKeys($term);

`

And with ` $optionsForElasticSearchRequest` ( ` limit`, ` page`).

 `
$primaryKeys=$this->searchAndReturnAssociationKeys($term,$optionsForElasticSearchRequest);

`

This is a really useful method, it can easily be added to any ` conditions` array.

 `
$conditions=array(
"{$this->alias}.{$this->primaryKey}"=>$this->searchAndReturnAssociationKeys('SearchTerm'),
);

`

If you are using the CakeDC/search plugin, you can use this to make subquery or query filters... (which is sweet!)

How to Search with results Sorted by best match

Search results are usually sorted by which results are the best match for the search term.

 `
$sortedIds=$this->searchAndReturnAssociationKeys('SearchTerm');
$results=$this->find('all',array(
'conditions'=>array(
"{$this->alias}.{$this->primaryKey}"=>$sortedIds
)
));
$results=$this->searchResultsResort($results,$sortedIds);

`

Convenience Search, Resort, and Return Data

If you want to just get search results, without any other conditions, it’s really simple:

 `
$findAllResults=$this->search($term)

`

And here are all the possible paramters...

 `
$findAllResults=$this->search($term,$optionsForFindAll,$optionsForElasticSearchRequest);

`

Background

This project is based in large part on the`Searchable/SearchIndex`_ Plugin/Behavior and my former fork of it. The original version stored all of the index data into a MySQL table with a full-text-index. That worked pretty well, but it only worked with the MyISAM table engine and it doesn’t offer all the sweet search syntax/features.

Initially, this was using the`Elasitc`_ Plugin/Datasource and it worked ok... but there were un-necissary complications due to the data storage patter (as CakePHP nested models) and because all of the data for all of the models was stored in the same “table” on ElasticSearch. Also the Elastic model required curl, not bad but not needed.

Now ElasticSearchIndex is using`Icing.Lib/ElasticSearch`_. for interactions with ElasticSearch.

It’s a little odd to interact with a “database” not through a “datasource” but the Lib is really an extension of the HttpSocket utility, and it’s indended to facilitate both a raw interactions (where you manually create whatever data you want to send) and it has tools to help automate simple data to pass.

Attribution

This project is an extension of Searchable/SearchIndex and informed by the Elastic DataSource... The base of the work is theirs. Big thanks!

and of course, you... pull requests welcome!

License

This code is licensed under the MIT License

Copyright (C) 2013–2014 Alan Blount alan@zeroasterisk.com https://github.com/zeroasterisk/

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

published on Jan 11, 2014 12:00 AM

Read more

CakePHP 3.0.0 dev preview 1 released

CakePHP 3.0.0 dev preview 1 released

The CakePHP core team is very excited to announce the first development preview of CakePHP 3.0

The CakePHP core team is very excited to announce the first development preview of CakePHP 3.0[1]. The team has been hard at work for the while, and we’re very excited and pleased with the progress we’ve made so far. Our goal with development preview releases like this is to gather early feedback about the changes coming in CakePHP 3.0. While a number of things will be changing in CakePHP 3.0, our focus for this release has been the ORM.

The Model layer in CakePHP has served the community very well for the past 8 years, but it has started to show its age. One of the goals of CakePHP 3.0 is to replace the ageing ORM with a more modern object- orientated implementation. This development preview has the underpinnings of the new ORM. The ORM has many of the features/methods you can expect in future 3.0 release, albeit with a few rough spots.

CakePHP 3.0 represents a significant break in backwards compatibility. One of the largest the project has ever had. We’re trying to modify existing methods and classes only where it’s required. However, modernizing the ORM has caused a significant ripple effect to other parts of the framework. You can expect fairly significant changes in everything that touches the ORM/Models as we’ve started over and built what we will become a great ORM.

Still a preview

We’d like to remind you that this is a development preview release. Many features are incomplete or missing. For example, the TreeBehavior and TranslateBehavior do not yet have 3.x versions. This release is not intended for production use, and should be considered alpha software. We are hoping that by releasing preview releases we can get feedback from you - the community - about CakePHP 3.0. The following features are known to be incomplete or broken. We will not be accepting any bug reports on these features at this time:

  • Console/cake bake does not work at this time.
  • FormHelper does not work with the new ORM yet.
  • SchemaShell has been removed.
  • Scaffold has been removed.
  • Many behaviors have been removed or are not working.
  • AclComponent is not working with DbAcl.

In addition to incomplete subsystems, many subsystems have had breaking API changes made to them. We recommend you checkout the migration guide[2] for more detail on which methods/classes have been changed.

Other improvements

In addition to the ORM we’ve improved other parts of the framework. A short list of improvements you an expect are:

  • Reverse routing has almost consistent time complexity now. In previous releases reverse routing performance decreased as the number of routes increased. Thanks to named routes and some additional optimizations routing performance should stay more consistent even with large numbers of routes.
  • Routing prefixes now map to controllers in sub-namespaces and not prefixed methods.
  • New HTTP client. The HttpSocket class has been entirely re-written. It is now simpler, more performant and easier to use.
  • Simplified configuration. While CakePHP does not have much configuration required. The configuration it does have is now much simpler and more transparent than ever before.
  • Community standards adopted. CakePHP is leveraging PSR-0, PSR-1 and composer support.
  • Streamlined events system. The events system is now simpler and more efficient than ever before.

Getting started

On top of the framework changes, we’ve created a new repository for the application skeleton[3]. You can install this and the development preview of CakePHP using composer[4]. After downloading and installing composer you can use:

$ php composer.phar create-project -s dev cakephp/app

This will generate a new application, so you can start experimenting with CakePHP 3.0.

Documentation online

While this is a preview release, we have been busy building documentation alongside the code changes. The in-development book[5] and API[6] are already online. They will be receiving frequent updates as more documentation and examples are written.

Getting involved

If you’re as excited about CakePHP 3.0 as we are, there are many ways you can get involved. You could help with the open issues in github[7], or provide your thoughts on any of the open RFC/Enhancement tickets. Both of these help us design and build the best framework we can. If you’re reading through the documentation and notice an error, please let us know, either by opening an issue or sending a pull request.

I’d like to thank everyone who has contributed thoughts, code, documentation or feedback to 3.0 so far. It’s going to be a major milestone for the project, and we’re just getting started with making it the best version of CakePHP ever.

Links

published on Jan 5, 2014 12:00 AM

Read more

CakePHP Community 2013

CakePHP Community 2013

2013 has been an incredible year for us, as it saw the CakePHP community grow stronger than ever.

CakePHP: the community driven framework

We’ve been very busy, and have a lot to show for it. Late last year we created the Community Center, as a central location for everyone to find their way around, and help people get involved with the project. This year we launched My CakePHP, as a hub for developers to create a profile, and unify the experience across all of our sites. The Cake Software Foundation website also received a well overdue facelift. Additionally, after continuous requests, and with a little help from CakeDC, we improved the schedule for the official CakePHP training, which is now provided on a regular basis.

Earlier this year we also announced our agreement with Microsoft to make CakePHP available on Windows Azure. That doesn’t mean you can’t get your piece of the cake on other platforms, such as Rackspace’s Cloud Sites, Amazon’s Elastic Beanstalk or RedHat’s OpenShift, as well as other PaaS providers, like Pagoda Box or Fortrabbit. There’s a lot to choose from.

It was also great to see that, since our efforts last year to extend the reach of the CakePHP community, both the Facebook interest page and our official Twitter account have reached over 10,000 likes and followers each. The official group on Facebook also surpassed 3,000 members, becoming even larger than groups for other major PHP frameworks. But the growth didn’t stop there. We had almost 1 million more visits to the CakePHP sites compared to last year, with the CookBook seeing nearly an additional 10 million page views, reaching over 26 million. For more numbers and stats check out this year’s community keynote.

Which takes us to San Francisco, USA, where we held CakeFest 2013, the annual conference dedicated to everything CakePHP. Over 80 developers from around the world joined us for 4 days of workshops and conference. We listened to your feedback from the previous year and broke the workshop schedule into beginner and advanced sessions over the first 2 days. This was then followed by another 2 days of 16 talks given by 12 international speakers, as well as keynotes, lightning talks, core team Q, and the raffle. We took away some really memorable moments, the best of all being the “Hour of Contribution”, where we saw everyone contributing to the project for an hour, in true open source fashion. It was a beautiful sight, and a humbling experience. Oh, and who could forget about the cake!

But wait, there’s more. Work has been going strong on version 3.0 of CakePHP, with the new ORM almost ready for it’s first developer preview release. The roadmap is slowly being completed, with the milestone available for anyone to join in on the fun. In the meantime, this year saw the release of versions 2.3 and 2.4 of the framework, with a sum of 28 releases in total. There’s also been a lot of activity in the developer community, with almost 6,000 additional questions tagged on Stack Overflow this past year alone. We also saw some interesting projects released, a couple of videos, interviews and books published, a few useful tools, as well as some nice cheat sheets. Not to mention some great initiatives, and of course, an honorable mention to core member Jose Gonzalez, who delivered a total of 25 successive posts on his blog as part of his CakePHP advent series. For all our Japanese developers, there was a similar series created previous years.

Overall, 2013 was an amazing year, and one to be proud of as a member of the community! A big thank you goes out to everyone who has been involved and helped make CakePHP what it is - a framework built by the community! Thank you.

published on Dec 29, 2013 12:00 AM

Read more

User Management Plugin with Twitter Bootstrap 3.x for cakephp 2.x version 2.3

User Management Plugin with Twitter Bootstrap 3.x for cakephp 2.x version 2.3

I have released a new version(2.3) of my plugin for user management. Demo at http://umpremium.ektanjali.com. This plugin has more than 100 features. This plugin is Basic need of your website. Basically It gives you all features which you need on starting your website or a project in cakephp 2.x framework.

This plugin has more than 100 features.

It is very helpful for Beginners because of following features-

Clean code with coding standards Proper documentations Newbie will learn- a. How to write code in Cakephp? b. How to use CSRF/XSS protection in cakephp c. How to use SSL/HTTPS in cakephp for whole site as well as only some pages. d. How to use Ajax Pagination in cakephp. e. How to use Ajax Form Validations in cakephp. f. How to use ajax search features.

and many more.

For all features, Beginners please have a look on http://developers.ektanjali.com/docs/umpremium/version2.3/beginners.html Experts will also learn many other things. For all features http://umpremium.ektanjali.com You can start your project or a website in few minutes with this plugin because this plugin has all things which you can think in starting of your project.

The main features are- Twitter Bootstrap framework 2.x and 3.x Login with Facebook, Twitter, Linkedin, Four Square, Gmail, Yahoo. All Configurations are database driven. No need to touch php code for config setting. No need to hard code your site URL any where. View Online users and guest and admin can take many action on online users. SSL support for selected pages or whole site. Most of the things are Ajax driven. Mailer system

I cannot describe all features here so please have a look on demo at http://umpremium.ektanjali.com here you can find all features of this plugin.

published on Dec 25, 2013 12:00 AM

Read more

CakePHP 2.4.4 released

CakePHP 2.4.4 released

The CakePHP core team is proud to announce the immediate availability of CakePHP 2.4.4.

The CakePHP core team is proud to announce the immediate availability of CakePHP 2.4.4. 2.4.4 is a bugfix release for the 2.4 release branch. A short list of the changes you can expect is:

  • TextHelper::autoLink() now handles email addresses inside URLs correctly.
  • Pagination request data is set even when a NotFoundException is raised now.
  • Model::deleteAll will only delete distinct records now.
  • Router::mapResources() now ensures that the prefix has both the leading and trailing slash.
  • An infinite loop condition in CakeSession was fixed. This could be triggered by starting an already invalidated session.
  • Hash::numeric() now works as expected with negative numbers and other numeric values.
  • The ‘my’ and ‘ym’ formats for Validation::date() have been relaxed to allow both 2 and 4 digit year values.
  • FormHelper will not infer types incorrectly when type=checkbox is provided.
  • Postgres biginteger primary keys now correctly use the bigserial type.
  • FormHelper::dateTime() correctly handles times around 12:00:00 when an interval is also used.
  • Hash::combine() now throws exceptions when the key and value paths result in arrays of differing lengths.
  • CakeRequest::referer() no longer incorrectly reads the HTTP_X_FORWARDED_HOST header.
  • CakeRequest::host() now has a trustProxy parameter that allows access to the proxy host value.

You can view the full changelog on cakephp.org[1]. I’d like to thank the people who have contributed to this release. Your bug tickets, documentation edits, and patches/pull requests are a big part of what keeps CakePHP alive and ticking. Download a packaged release on github[2].

Links

published on Dec 24, 2013 12:00 AM

Read more

CakePHP 2.4.3 released

CakePHP 2.4.3 released

The CakePHP core team is proud to announce the immediate availability of CakePHP 2.4.3.

The CakePHP core team is proud to announce the immediate availability of CakePHP 2.4.3. 2.4.3 is a bugfix release for the 2.4 release branch. A short list of the changes you can expect is:

  • API Documentation improvements.
  • Long headers are no longer wrapped with PHP_EOL when sending email with MailTransport. This should solve delivery issues with Qmail, and other SMTP transport agents.
  • Model::_clearCache() has improved performance.
  • Model’s now work better with schema’s containing numeric column names.
  • An exception is now raised when a view block is opened while it is already open.
  • SchemaShell no longer uses schema.php as the filename when a custom name parameter is provided.
  • MKV is a supported content type.
  • CookieComponent writes are now more consistent. Previously writing multi-key and single writes were handled very differently. Fixing the write consistency makes deletion data saner and results in fewer cookies being transmitted.
  • Empty array data in cookies is now parsed correctly.
  • CakeTime::dayAsSQL() now correct supports the timezone parameter.
  • COUNT(DISTINCT x) queries work better in SQLServer now.
  • Postgres sequence values now use custom primary keys.
  • HtmlHelper now correctly encodes URLs generated for meta tags.
  • Using FormHelper::postLink() after creating a GET form now works as expected.
  • Model::saveAssociated() handles expression objects correctly now.
  • Model::setSource() does not alter the datasource’s cacheSources property anymore.
  • Non-breaking spaces are now removed by Inflector::slug()

You can view the full changelog on cakephp.org[1]. I’d like to thank the people who have contributed to this release. Your bug tickets, documentation edits, and patches/pull requests are a big part of what keeps CakePHP alive and ticking. Download a packaged release on github[2].

Links

published on Nov 25, 2013 12:00 AM

Read more

CakePHP 2.4.2 released

CakePHP 2.4.2 released

The CakePHP core team is proud to announce the immediate availability of CakePHP 2.4.2.

The CakePHP core team is proud to announce the immediate availability of CakePHP 2.4.2[1]. 2.4.2 is a bugfix release for the 2.4 release branch. A short list of the changes you can expect is:

  • Sqlite::truncate() will verify that the sqlite_sequence table exists before modifying it.
  • Label elements now have their for attributes generated correctly for radio inputs.
  • Improved API documentation for a number of classes and methods.
  • TreeBehavior::recover() now correctly uses the scope conditions.
  • Hash::contains() can now look for needle values containing nulls.
  • Disabled radio buttons are now generated correctly when integer and string keys are used.
  • International domains are now accepted by Validation::url()
  • Inflector now handles ‘quota’ and ‘curves’ correctly.
  • jQueryEngineHelper now treats the ‘xhr’ option as a callback argument.
  • Bake now adds the numeric validator for float fields.
  • DboSource::renderStatement() now trims whitespace from generated queries.

As always, a big thank you to everyone involved in both contributions through commits, tickets, documentation edits, and those whom have otherwise contributed to the framework. Without you there would be no CakePHP. Download a packaged release [2].

Links

published on Oct 23, 2013 12:00 AM

Read more

Issues have moved to Github

Issues have moved to Github

The CakePHP team is happy to announce that as of today both issues and pull requests will be managed at github.

The CakePHP team is happy to announce that as of today both issues and pull requests will be managed at github. We have archived the lighthouse projects and made them read-only. All open tickets from lighthouse have been migrated to their respective github projects. We’ll be continuing to wrangle and update tickets in github over the next few days. We’ll also be updating the links on the various CakePHP sites to reflect this change, and ask your patience while we get all the information updated.

Why change?

While moving bug trackers is rarely a pleasant experience, we think the move to github will be positive for the community. Since our move to lighthouse in 2009, the ticket management features provided by github have improved dramatically. With excellent search and tight integration with pull requests we feel the ticketing features provided by github now offer a number of advantages over lighthouse. We hope that moving issues to github makes it easier and simpler for new and existing contributors to continue making CakePHP a fantastic project. We’d like to thank lighthouse for the excellent service and hosting over the past 4 years.

published on Oct 12, 2013 12:00 AM

Read more

CakePHP 2.4.1 released

CakePHP 2.4.1 released

The CakePHP core team is proud to announce the immediate availability of CakePHP 2.4.1[1]. 2.4.1 is a bugfix release for the 2.4 release branch.

The CakePHP core team is proud to announce the immediate availability of CakePHP 2.4.1[1]. 2.4.1 is a bugfix release for the 2.4 release branch. A short list of the changes you can expect is:

  • Improved API documentation and links to the book from the API.
  • Notice errors when loading LC_TIME files should no longer happen.
  • TreeBehavior::generateTreeList() now includes the scope defined in the model’s actsAs property.
  • Support for readline was added to Shell commands. If your environment supports readline, arrow keys will no longer output escape sequences.
  • FormHelper::input() will now use attributes defined in the label key.
  • Inflection support was improved.
  • Performance of CakeTime::timeAgoInWords() was improved.
  • Method signatures of Behavior callbacks was corrected. If you are using PHP5.4 you may have to update the method signatures of your behaviors to resolve any E_STRICT errors.
  • CROSS JOINs work correctly now.
  • SqlServer::value() now correctly handles NULL values.
  • Cache::clearGroup() with FileEngine and no prefix behaves as expected now.
  • CakeEmail now quotes email aliases that contain non-alphanumeric characters, that have not already been encoded.
  • Phone number validation was simplified to fix valid area codes being detected as invalid.

Security disclosure

In 2.3.8 a security issue in AssetDispatcher was fixed. In the spirit of being open and transparent a more detailed description of the issue is being provided. By carefully crafting a URL the AssetDispatcher would allow arbitrary file access. A successful attack required at least one theme or plugin to be in use. An example url would look like:

http://example.com/DebugKit/%2e.//%2e.//%2e.//%2e.//%2e.//%2e.//%2e.//%2e.//%2e.//%2e.//%2e.//%2e.//%2e./etc/passwd

AssetDispatcher incorrectly checked for directory traversal before decoding the URL. We’d like to thank Takeshi Terada of Mitsui Bussan Secure Directions, Inc for notifying us of the issue.

As always, a big thank you to everyone involved in both contributions through commits, tickets, documentation edits, and those whom have otherwise contributed to the framework. Without you there would be no CakePHP. Download a packaged release [2].

Links

published on Sep 15, 2013 12:00 AM

Read more

Plugin for Paypal Web Payments Pro for Cake PHP 2.x

Plugin for Paypal Web Payments Pro for Cake PHP 2.x

Basic Plugin that uses the NVP Methods for the WPP API from Paypal. Component pushes method and NVP combo to paypal url curl. Required php5-curl configuration in php.

PayPal WebPaymentsPro (WPP) Plugin for CakePHP 2.x

CakePHP 2.x Plugin for interfacing with Paypal WPP

Plugin can be found at https://bitbucket.org/chrispierce/paypalwpp-plugin-for-cakephp-2.x/overview

Usage

Load plugin in your APP and enable it by using the following bootstrap.php config:

 `
CakePlugin::load('PaypalWPP');
`

Configure your account by opening the Config/paypal.php file as follows

 `
$config=array(
'paypal'=>array(
'username'=>'username_api1.domain.com',
'password'=>'THGSWS658IKUN79S',
'signature'=>'AFYn4irhcVyzOOiJkc.H2zPIuztlArzO7mr5uXMO6DLICAE85JF.H5PPp',
'endpoint'=>'https://api-3t.paypal.com/nvp',
'version'=>'53.0',
),
);
`

Load the Component into the controller of your choice.

 `
public$components=array(
'PaypalWPP.PaypalWPP',
);
`

Next urlencode your data and send it to the component using a method and an nvp. For doing payments using DoDirectPayment (https://developer.paypal.com/webapps/developer/docs/classic/api/merchant/DoDirectPayment_API_Operation_NVP/) the following example would work:

 `
publicfunctionadd(){
if($this->request->is('post')||$this->request->is('put')){
$firstName=urlencode($this->request->data['Sale']['first_name']);
$lastName=urlencode($this->request->data['Sale']['last_name']);
$creditCardType=urlencode($this->request->data['Sale']['card_type']);
$creditCardNumber=urlencode($this->request->data['Sale']['card_number']);
$expDateMonth=$this->request->data['Sale']['exp']['month'];
$padDateMonth=urlencode(str_pad($expDateMonth,2,'0',STR_PAD_LEFT));
$expDateYear=urlencode($this->request->data['Sale']['exp']['year']);
$cvv2Number=urlencode($this->request->data['Sale']['cvv2']);
$amount=urlencode($this->request->data['Sale']['amount']);
$nvp='&PAYMENTACTION=Sale';
$nvp.='&AMT='.$amount;
$nvp.='&CREDITCARDTYPE='.$creditCardType;
$nvp.='&ACCT='.$creditCardNumber;
$nvp.='&CVV2='.$cvv2Number;
$nvp.='&EXPDATE='.$padDateMonth.$expDateYear;
$nvp.='&FIRSTNAME='.$firstName;
$nvp.='&LASTNAME='.$lastName;
$nvp.='&COUNTRYCODE=US&CURRENCYCODE=USD';

$response=$this->PaypalWPP->wpp_hash('DoDirectPayment',$nvp);
if($response['ACK']=='Success'){
$this->Session->setFlash('PaymentSuccessful');
}else{
$this->Session->setFlash('PaymentFailed');
}
debug($response);
}
}
`

Other Methods can be found at https://devtools-paypal.com/apiexplorer/PayPalAPIs

published on Sep 11, 2013 12:00 AM

Read more

CakePHP 2.4.0 is ready

CakePHP 2.4.0 is ready

The CakePHP core team is proud to announce the immediate availability of CakePHP 2.4.0 and 2.3.10[1]. There have been a few small improvements and fixes since the release of 2.4.0-RC2.

CakePHP 2.4.0

CakePHP 2.4.0 is now marked as stable. It is a new version in the 2.x series that is API compatible with other releases in the 2.x series. Make sure you read the migration guide [2] before upgrading as there are a few changes you may need to make.

A quick overview of the changes in 2.4 are:

  • The constants IMAGES_URL, JS_URL, CSS_URL have been deprecated and replaced with config variables App.imageBaseUrl, App.jsBaseUrl, App.cssBaseUrl respectively. Each of the deprecated constants will be removed in 3.0.
  • The CAKEPHP_SHELL constant has been deprecated and will be removed in 3.0.
  • Sanitize class has been deprecated and will be removed in 3.0.
  • FileLogs can now have a max size and simple rotation configured.
  • Logging now support syslog out of the box.
  • A number of locales have been renamed.
  • JSONP support has been added to the JsonView
  • You can disable updating counterCache values with the counterCache option when saving models.
  • Password hashing has been extracted into a set of PasswordHasher classes. These classes make changing out password hashing strategies for the various authentication adapters simple.
  • Stateless authentication has been improved.

For a full list of the changes and improvements you should review the 2.4 Migration guide [2].

Changes to 2.4.0 since 2.4.0-RC2

  • confirm handlers are now correctly encoded.
  • Helpers are now loaded during View construction. This ensures that helpers are always available.
  • View blocks can now operate on any object that can be converted to a string.
  • All changes detailed in the 2.3.10 changelogs are also included with 2.4.0

CakePHP 2.3.10

2.3.10 marks the end of normal bug fix releases for 2.3.x. Security fixes will continue to be released for 2.3.x until 2.6.0. The following is a short list of issues fixed and changes you can find in 2.3.10

  • Configuration values are now merged between Emails and their transports.
  • CakeTime::timeAgoInWords() now uses ‘about X ago’ when the time delta is lower than accuracy.
  • DbAcl now uses INNER joins instead of LEFT joins. This yields improved performance with some database vendors.
  • CakeEmail::template() can now disable the layout as documented.
  • Number formatting in locales that use ‘,’ for a decimal separator is now correct.
  • RedirectRoute now honors the ‘persist’ parameter correctly.
  • Constants are now conditionally defined in ShellDispatcher.
  • session.auto_start is no longer set as it never worked and triggers errors in PHP 5.5.
  • Sqlite now generates schema correctly when BIGINT columns are used as a primary key.
  • FileCache now removes special characters that would cause issues on windows systems.
  • i18n shell now correctly extracts categories other than LC_MESSAGES.

Development continues to progress on 3.0 with pull requests being frequently opened. Work has also begun on 2.5, another API compatible release in the 2.x line of releases. A huge thanks to all involved in terms of both contributions through commits, tickets, documentation edits, and those whom have otherwise contributed to the framework. Without you there would be no CakePHP. Download a packaged release [3].

Links

published on Aug 30, 2013 12:00 AM

Read more

Generating Tree compatible with twitter bootstrap nav subnav

Generating Tree compatible with twitter bootstrap nav subnav

I needed a helper which show my Menu items in twitter bootstrap navigation bar format with unlimited deep. First i did google for finding it but there was no result or there was not free. So i will show you how i did do that. first of all: My MenuItems Model has simple fields: id,parent_id,title,link,lft,rght and it’s actsAs Tree (Behavior)

so after i fetched data in threaded mode with find function i passed it to this little tiny long time function in a helper:

public function renderMenu($array,$root=true,$hasChildren=false) {
    if (count($array)) {
        if ($root)
            echo "\n<ul class=\"nav\">\n";
        else
            if ($hasChildren)
                echo "\n<ul class=\"dropdown-menu\">\n" ;
            else
                echo "\n<ul>\n";
        foreach ($array as $vals) {

            if (count($vals['children']) && (!$hasChildren))
                $liClass="dropdown" ;
            else
                                if ($hasChildren && count($vals['children']))
                                        $liClass = 'dropdown-submenu' ;
                                else
                                        $liClass=null ;


            echo "<li " ;
            if (!is_null($liClass))
                echo 'class="'.$liClass.'"' ;

            echo " id=\"".$vals['MenuItem']['id']."\">".$this->Html->link($vals['MenuItem']['title'],$vals['MenuItem']['link'],array('class'=>'dropdown-toggle', 'data-toggle'=>'dropdown'));
            if (count($vals['children'])) {
                $this->renderMenu($vals['children'],false,true);
            }
            echo "</li>\n";
        }
        echo "</ul>\n";
    }
}

it will print out a Bootstrap navigation bar compatible nested ul li.

Regards

published on Aug 28, 2013 12:00 AM

Read more

Bootstrap 3 Formhelper (CakePHP 2.x)

Bootstrap 3 Formhelper (CakePHP 2.x)

A little FormHelper for horizontal Bootstrap3-compatible forms in CakePHP 2.x.

Hi,

Nothing really big but never the less it might be useful to some people:

I wrote a little BootstrapFormHelper which will create Bootstrap3-compatible Forms via the normal FormHelper-Calls. You do not need to change any views for this.

https://gist.github.com/Suven/6325905

If you have feedback or suggestions, feel free to tell them (:

published on Aug 24, 2013 12:00 AM

Read more

CakePHP 2.4.0-RC2 released

CakePHP 2.4.0-RC2 released

The CakePHP core team is happy to announce the immediate availability of the second release candidate for 2.4.0[1].

The CakePHP core team is happy to announce the immediate availability of the second release candidate for 2.4.0[1].

CakeFest 2013[2] is just around the corner. If you haven’t already bought your ticket do it now. It will be a great time to learn way beyond just CakePHP, this year we feature talks about performance, the future of PHP and modern javascript frontend frameworks. The core team is making great strides for having a new stable version for CakeFest and workshops will be based off the great new features next release is included.

A short list of changes you can expect in 2.4.0-RC2 are:

  • Config data between Email and Transport classes now merges correctly.
  • CakeTime::timeAgoInWords() uses fuzzy terms when time is below thresholds.
  • Confirm values are now correctly encoded. This was a regression introduced in 2.4.0-RC1.
  • DbAcl uses INNER joins instead of LEFT joins to help increase performance.
  • CakeEmail::template() can now disable rendering the layout as documented.
  • Formatting number in european locales now works correctly.
  • Translation strings were updated to exclude non-translable content.
  • RedirectRoute now persists parameters using the same methods as normal routes.
  • Components with settings are now mocked better.

A huge thanks to all involved in terms of both contributions through commits, tickets, documentation edits, and those whom have otherwise contributed to the framework. Without you there would be no CakePHP. Download a packaged release [3].

Links

published on Aug 19, 2013 12:00 AM

Read more

CakePHP 2.4.0-RC1 and 2.3.9 released

CakePHP 2.4.0-RC1 and 2.3.9 released

The CakePHP core team is happy to announce the immediate availability of the first release candidate for 2.4.0 and a new maintenance release for the 2.3 branch.

The CakePHP core team is happy to announce the immediate availability of the first release candidate for 2.4.0[1] and a new maintenance release for the 2.3 branch[2].

As the date for CakeFest 2013[3] comes closer, you should be thinking on buying a ticket if haven’t already. It will be a great time to learn way beyond just CakePHP, this year we feature talks about performance, the future of PHP and modern javascript frontend frameworks. The core team is making great strides for having a new stable version for CakeFest and workshops will be based off the great new features next release is including.

A short list of changes you can expect in 2.4.0-RC1 are:

  • Support for query parameters on Router::parse()
  • Add option to send email attachment from string in CakeEmail
  • Allow variable aliasing when using _serialize for the JsonView and XmlView. It also support pretty printing when available
  • Improving phone validation for USA and Canada
  • New option to multiply decimal percentages in CakeNumber::toPercentage()
  • Ability to provide custom strings for timeAgoInWords()
  • Minutes display with FormHelper can now be rounded to the next or previous custom value
  • PaginatorHelper won’t display the first page argument for the first page, to avoid duplication on search engines
  • Added CakeResponse::location() to quickly send redirect status codes and location
  • Ability to set multiple headers at once with CakeRespose::header()
  • Improved handling of response codes to avoid sending invalid HTTP responses
  • Added SSL support to MySQL PDO connections
  • IMAGES_URL, CSS_URL, JS_URL are now deprecated and can be controlled with a new Configure value
  • ConsoleShell was also deprecated
  • Support for setting full URLs in css/js/image constants and configure values
  • CakeTestCase::getMockForModel() is now smarted and can mock AppModel
  • Deprecated DEFAULT_LANGUAGE constant
  • Deprecated Sanitize class
  • Missing directories under tmp used for logging and caching are now created automatically in debug mode

Maintenance release 2.3.9 incorporates over 20 bugfixes and some performance improvements, developers are encouraged to upgrade their apps to profit from these changes.

A huge thanks to all involved in terms of both contributions through commits, tickets, documentation edits, and those whom have otherwise contributed to the framework. Without you there would be no CakePHP. Download a packaged release [4].

Links

published on Aug 11, 2013 12:00 AM

Read more

Search plug-in for CakePHP 2

Search plug-in for CakePHP 2

This plug-in allows basic but flawlessl accent-insensitive text search and result highlighting.

Searching texts in a database and highlighting matches in results display is a very common functionality on websites. It can be quite hard and very frustrating to implement when dealing with languages that use Unicode special characters (mainly accentuated letters), since no universal and complete method exists to correctly de- accentuate text. Furthermore, Unicode characters double-byte encoding makes the standard PHP string functions unreliable since it makes characters indexes inconsistent between the de-accentuated text and the original one.

This plug-in takes care of these issues. It consists mainly of a Behavior that makes a custom ‘search’ find type available to Models, with special options for database filtering and result highlighting. It also contains a Lib class, mainly for use by the Behavior but this class has a static function to strip the accents from a text that you can use besides the search functionality.

The functionalities of this plug-in are still very basic, but will be improved in the future, probably starting with results ordering.

Links

Search demo Github repository More explanations on searching with accents in PHP and MySQL

published on Jul 23, 2013 12:00 AM

Read more

NeptunIDE - CakePHP dedicated IDE is now available for everyone!

NeptunIDE - CakePHP dedicated IDE is now available for everyone!

Two years ago I posted here about my new project - NeptunIDE, a cloud-based IDE supporting CakePHP.

I was looking for Beta testers and there were many responses, much more than we could actually handle at that time.

After two years of intensive development NeptunIDE is nearly ready, and to celebrate this we are opening NeptunIDE Beta today. In the next couple of days anyone can register and start using NeptunIDE beta immediately - and totally for free. I’d say that it’s ready to use for production development.

What makes NeptunIDE so special? It’s the first IDE with dedicated CakePHP support.

And what does it mean? It means you can start developing a new CakePHP project with just a few clicks. It means you can run an action you are working on by pressing F5 on your keyboard (no matter if you are editing controller method, view or even CakePHP shell - shell will be executed in NeptunIDE built-in terminal).

And last, but definitely not least: it means that NeptunIDE will provide CakePHP autocomplete sugestions based on CakePHP conventions. No other IDE can provide this by analysing PHP Code. Imagine it: you type ` $components` in your controller and NeptunIDE suggests you names of all CakePHP components in your project. You type ` $this->Html->link` in view and NeptunIDE suggests you the list of controllers and actions that you can link to. You style your CakePHP project and NeptunIDE suggests automagically created css classes in your css files.

Well, you don’t have to imagine this. You can see it with your own eyes now! Just sign up for 100% free Beta at neptunide.com. Hurry up! Free Beta subscription is available only until the end of July 2013 and will run until the end of August 2013.

published on Jul 23, 2013 12:00 AM

Read more

Document Manager Plugin for CakePHP 2.x

Document Manager Plugin for CakePHP 2.x

This plugin offers the the possibility to have an online browser allowing to manage files inside a directory tree. You can upload, rename, delete files, create folders, get the absolute URL of a file and much more...

The Document Manager plugin provides an out of the box simple file management interface for any CakePHP 2.x application.

You define a base directory inside the webroot folder for your arborescence and inside you can create folders, upload/rename/delete files, browse them, obtain the absolute URL of any file in order to be able to link to it. Uploaded files informations are stored inside a Document table which allows to easily access them in your application.

Moreover it can be hooked to an user management system to manage ownership of files and prevent files edition or deletion by other users. If you do not have an user management system, you can easily disable file ownership management to have an open system.

It requires jQuery and jQuery-UI to perform. It is styled with Bootstrap.

The source code can be found on GitHub : Document Manager Plugin for CakePHP. More informations at La Pâtisserie.

published on Jul 18, 2013 12:00 AM

Read more

CakePHP 2.3.8 & 2.2.9 released

CakePHP 2.3.8 & 2.2.9 released

The CakePHP core team is happy to announce the immediate availability of 2.3.8[1] and 2.2.9[2]. These releases contain security fixes and are recommended for all CakePHP developers.

The CakePHP core team is happy to announce the immediate availability of 2.3.8[1] and 2.2.9[2]. These releases contain security fixes and are recommended for all CakePHP developers. A short list of changes you can expect in 2.3.8 are:

  • Improved API documentation.
  • I18nShell now extracts plugin model validation messages correctly.
  • ServerShell now serves static assets with query string parameters.
  • ServerShell correctly uses the document_root parameter.
  • Inflector can now pluralize additional words.
  • File responses using HTTP Range now work correctly.
  • A regression introduced to AuthComponent in 2.3.7 for redirectUrl() when an application is running in a subdirectory has been fixed.
  • Pagination sort whitelists are now trusted implicitly. No additional validation is done on whitelisted fields. This makes it easier to sort on synthetic columns, or columns added through joins in custom finds.

As previously mentioned, a security issue related to the AssetDispatcher was fixed. This upgrade is important for all applications serving assets out of themes or plugins using the built- in AssetDispatcher. A big thank you to Takeshi Terada of Mitsui Bussan Secure Directions for contacting us about the security issue and providing steps to reproduce it. We’ll disclose more details about the vulnerability in the future once people have had the chance to upgrade.

A huge thanks to all involved in terms of both contributions through commits, tickets, documentation edits, and those whom have otherwise contributed to the framework. Without you there would be no CakePHP. Download a packaged release [4].

Links

published on Jul 18, 2013 12:00 AM

Read more

CakeFest 2013: San Francisco, USA

CakeFest 2013: San Francisco, USA

Join us at CakeFest 2013, the annual CakePHP conference, held this year in San Francisco, from the 29th of August until the 1st of September, and experience open source at it’s very best! Visit http://cakefest.org for info and tickets.

One event for everything CakePHP

We want to celebrate 8 years of CakePHP with you and the whole community, and how better than to host our annual conference in the awesome city of San Francisco! Don’t miss out on this unique event dedicated to the framework.

Workshops

The 2 days of workshops at CakeFest are an ideal opportunity to learn the ins and outs of CakePHP, and a great way to get up to speed with the latest versions and innovations from the framework. Attendees will also receive their own certificate of attendance. This year we have both basic and advanced workshops, ranging from getting the most out of CakePHP, to going deep into the internals of the project, allowing both beginners and veterans to get a piece of the cake!

Conference

Covering 2 fully packed days of keynotes, presentations and talks on CakePHP and related technologies, the conference portion of CakeFest is an event not to be missed, for both new and old users of the framework. It’s a great time to engage and network with the community, learn from other experienced developers, and party with the core team! See http://cakefest.org/schedule for more details.

Sponsors

This year we’ve teamed up with some big names in the industry, to make this the biggest and best CakePHP conference ever! These people, organisations and companies help make everything happen, so be sure to check them out at http://cakefest.org/sponsors and say hello.

Event

The event itself is held from Thursday, the 29th of August, until Sunday, the 1st of September. The first 2 days are dedicated to the workshops, while the weekend sees the 2 conference days through to the closing of the conference.

There are tickets for only the workshops, just the conference days, or the full event (recommended), and currently we have an early bird discount on prices which will end on Monday the 22nd of July.

Oh, and... did we mention there will be cake? See you there!

Get your tickets now at http://cakefest.org/tickets.

published on Jul 17, 2013 12:00 AM

Read more

CakePHP 2.3.7 & 2.4.0-beta released

CakePHP 2.3.7 & 2.4.0-beta released

The CakePHP core team is proud to announce the immediate availability of CakePHP 2.3.7 & 2.4.0-beta. 2.3.7 is a bugfix release for the 2.3 branch, while 2.4.0-beta is the first release of the 2.4 branch

The CakePHP core team is proud to announce the immediate availability of CakePHP 2.3.7 & 2.4.0-beta[1]. 2.3.7 is a bugfix release for the 2.3 branch, while 2.4.0-beta is the first release of the 2.4 branch. A short list of the changes you can expect in 2.3.7 are:

  • Cached views now contain their Content-Type header. It is recommended that you flush your view caches when upgrading.
  • Return-Path is now excluded on emails delivered via SMTP.
  • The automatic created & modified times when saving records are now consistent. There used to be an edge case where they could differ by one second.
  • Undocumented, untested features around the IIS_SERVER constant have been removed.
  • FormHelper::dateTime() now selects the correct year when creating an input which has a maxYear earlier than the current year.
  • Email views now calculate the boundary later in the rendering process fixing issues where View callbacks could append inline images or attachments, resulting in incorrect boundary markers.
  • AuthComponent now correctly generates redirect URL’s when the application base path matches the controller name.
  • Errors generated from requests containing ‘index.php’ now render correctly.
  • Classnames containing ‘..’ are now rejected.

There was a security fix in this release that fixes an issue where controllers outside of the application could be loaded under certain conditions. This is an important upgrade for applications that accept uploaded PHP files where user data is used to determine the final file name. In these situations it would be possible for an attacker to upload a PHP file and remotely execute code. A big thanks to Adrian Ulrich for contacting us about the issue, and providing steps to reproduce it.

2.4.0-beta

The 2.4.0-beta release contains several new features that improve CakePHP’s performance, security and ease of use. When done, this new version is intended to be a replacement for the 2.3.x branch. A migration guide is provided in the book [2] and we encourage you to read it if you are upgrading from an older version.

The current list of the new features & changes you can expect in 2.4.0:

Console

  • Logged notice messages will now be colourized in terminals that support colours.

SchemaShell

  • cake schema generate now supports the –exclude parameter.

BakeShell

  • cake bake model now supports baking $behaviors. Finding lft, rght and parent_id fields in your table it will add the Tree behavior, for example. You can also extend the ModelTask to support your own behaviors to be recognized.

FixtureTask

  • cake bake fixture now supports a –schema parameter to allow baking all fixtures with noninteractive “all” while using schema import.

Object

  • Object::log() had the $scope parameter added.

Components

AuthComponent

  • AuthComponent now supports proper stateless mode when using Basic or Digest authenticators. Starting of session can be prevented by setting AuthComponent::$sessionKey to false. Also now when using only Basic or Digest you are no longer redirected to login page. For more info check the AuthComponent page.
  • Property AuthComponent::$authError can be set to boolean false to suppress flash message from being displayed.

PasswordHasher

  • Authenticating objects now use new password hasher objects for password hash generation and checking.

Models

  • Model::save(), Model::saveField(), Model::saveAll(), ` Model::saveAssociated()`, Model::saveMany() now take a new ` counterCache` option. You can set it to false to avoid updating counter cache values for the particular save operation.
  • Model::clear() was added.

Datasource

  • Mysql, Postgres, and SQLserver now support a ‘settings’ array in the connection definition. This key => value pair will be issued as SET commands when the connection is created.

View

JsonView

  • JSONP support has been added to :php:class: JsonView.

HtmlHelper

  • The API for HtmlHelper::css() has been changed.
  • New option escapeTitle added to HtmlHelper::link() to control escaping of only link title and not attributes.

TextHelper

  • TextHelper::autoParagraph() has been added. It allows to automatically convert text into HTML paragraphs.

PaginatorHelper

  • PaginatorHelper::param() has been added.

Network

CakeRequest

  • CakeRequest::param() has been added.
  • CakeRequest::is() has been modified to support an array of types and will return true if the request matches any type.
  • CakeRequest::isAll() has been added to check that a request matches all the given types.

CakeEmail

  • Logged email messages now have the scope of email by default. If you are not seeing email contents in your logs, be sure to add the email scope to your logging configuration.

HttpSocket

  • HttpSocket::patch() has been added.

L10n

  • ell is now the default locale for Greek as specified by ISO 639-3 and gre its alias. The locale folders have to be adjusted accordingly (from /Locale/gre/ to /Locale/ell/).
  • fas is now the default locale for Farsi as specified by ISO 639-3 and per its alias. The locale folders have to be adjusted accordingly (from /Locale/per/ to /Locale/fas/).
  • sme is now the default locale for Sami as specified by ISO 639-3 and smi its alias. The locale folders have to be adjusted accordingly (from /Locale/smi/ to /Locale/sme/).
  • mkd replaces mk as default locale for Macedonian as specified by ISO 639-3. The corresponding locale folders have to be adjusted, as well.
  • Catalog code in has been dropped in favor of id (Indonesian), e has been dropped in favor of el (Greek), n has been dropped in favor of nl (Dutch), p has been dropped in favor of pl (Polish), sz has been dropped in favor of se (Sami).
  • Kazakh has been added with kaz as locale and kk as catalog code.
  • Kalaallisut has been added with kal as locale and kl as catalog code.

Logging

  • Log engines do not need the suffix Log anymore in their setup configuration. So for the FileLog engine it suffices to define ‘engine’=>’File’ now. This unifies the way engines are named in configuration (see Cache engines for example). Note: If you have a Log engine like DatabaseLogger that does not follow the convention of using the Log suffix, you will have to adjust your class name to ` DatabaseLog`. You should also avoid class names like SomeLogLog which include the suffix twice at the end.

FileLog

  • Two new config options size and rotate have been added for FileLog engine.

SyslogLog

  • The new logging engine SyslogLog was added to stream messages to syslog.

Utility

  • pr no longer outputs HTML when running in cli mode.

Validation

  • Validation::date() now supports the y and ym formats.
  • The country code of Validation::phone() for Canada has been changed from can to ca to unify the country codes for validation methods according to ISO 3166 (two letter codes).

CakeNumber

  • The currencies AUD, CAD and JPY have been added.
  • The symbols for GBP and EUR are now UTF-8. If you upgrade a non-UTF-8 application, make sure that you update the static $_currencies attribute with the appropriate HTML entity symbols (&#163; and &#8364;) before you use those currencies.

CakeTime

  • CakeTime::isPast() and CakeTime::isFuture() were added.

Xml

  • New option pretty has been added to Xml::fromArray() to return nicely formatted Xml.

Error

ErrorHandler

  • New configuration option skipLog has been added, to allow skipping certain Exception types to be logged. Configure::write(‘Exc eption.skipLog’,array(‘NotFoundException’,’ForbiddenException’)); will skip logging these exceptions and the ones extending them when ` ‘Exception.log’` config is true

Routing

Router

  • Router::baseUrl() was added. This method replaces ` FULL_BASE_URL`. Which is now deprecated.

The API docs[3] and cookbook have been updated to reflect the changes and updates for 2.4.0.

A huge thanks to all involved in terms of both contributions through commits, tickets, documentation edits, and those whom have otherwise contributed to the framework. Without you there would be no CakePHP. Download a packaged release [4].

Links

published on Jul 5, 2013 12:00 AM

Read more

Croogo 1.5.2 API

Croogo 1.5.2 API

Croogo 1.5.2 API generate with Apigen

https://github.com/rafaeldecruzeiro/croogoapi_1.5.2

published on Jun 25, 2013 12:00 AM

Read more

CakePHP 1.3.17 Released - Important upgrade for 1.3

CakePHP 1.3.17 Released - Important upgrade for 1.3

CakePHP 1.3.17 has been released. This is an important update for all users of 1.3. It is recommended that all users of 1.3 should upgrade as soon as possible.

CakePHP 1.3.17 has been released. This is an important update for all users of 1.3. It is recommended that all users of 1.3 should upgrade as soon as possible.

In the previous release for 1.3.16 a mistake was made when creating the 1.3.16 tag. An important fix was missed from the packaged release. We recommend that all applications using 1.3 upgrade to 1.3.17 immediately safeguard against the SQL injection issue that 1.3.16 was intended to fix.

How did this happen?

When creating the package for 1.3.16, a git clone was not correctly updated before generating the new tag. To prevent this issue in the future, we’ll be updating the automated build script used to package CakePHP to always update the local clone. This should prevent similar errors in the future.

Links

published on Jun 25, 2013 12:00 AM

Read more

CakePHP 2 Export as CSV plugin

CakePHP 2 Export as CSV plugin

The Export as CSV plugin takes the results of a Model find(‘all’) call, including nested belongsTo associations, flattens the resulting array, and exports it as a CSV.

Exporting a flat keys/values array as a CSV is pretty simple.

Exporting the results of a Model find(‘all’) call, when there are multiple nested belongsTo associations, when not every association exists for every record, etc. is a bit more complex.

This plugin flattens out such an array and exports it as CSV.

Source and documentation available on GitHub: https://github.com/joshuapaling/CakePHP-Export-CSV-Plugin

Example Usage

var $components = array('Export.Export');

public function export_data() {
    $data = $this->MyModel->find('all');
    $this->Export->exportCsv($data);
}

Options

The exportCsv() function has 5 params:

  1. $data - an array of data to export. This array should be of the format returned by a call to $this->MyModel->find(‘all’);
  2. $fileName (optional) - the name of the file to download. If blank, it will use a date-stamped name like export_2013-09-24.csv
  3. $maxExecutionSeconds (optional) - if set, this will change the PHP max_execution_time. Useful when dealing with large amounts of data.
  4. $delimiter (optional) - The delimiter for your CSV. Defaults to comma (,).
  5. $enclosure (optional) - The enclosure for your CSV. Defaults to double-quote (”).

Example input / output

Lets say City belongsTo State, which belongsTo country. You might fetch data from the City model looking something like this:

array(
    0 => array(
        'City' => array(
            'name' => 'Sydney',
            'population' => '4.6m'
        ),
        'State' => array(
            'name' => 'NSW',
            'Country' => array(
                'name' => 'Australia',
            )
        )
    ),
    1 => array(
        'City' => array(
            'name' => 'Melbourne',
            'population' => '4.1m'
        ),
        'State' => array(
            'name' => 'VIC',
            'Country' => array(
                'name' => 'Australia',
            )
        )
    ),
)

And the export component will output a CSV like this:

<table cellpadding=”7” > <tr> <th>City.name</th> <th>City.population</th> <th>State.name</th> <th>State.Country.name</th> </tr> <tr> <td>Sydney</td> <td>4.6m</td> <td>NSW</td> <td>Australia</td> </tr> <tr> <td>Melbourne</td> <td>4.1m</td> <td>VIC</td> <td>Australia</td> </tr></table>

License

MIT - http://opensource.org/licenses/MIT

published on Jun 23, 2013 12:00 AM

Read more

CakePHP 2.3.6 released

CakePHP 2.3.6 released

The CakePHP core team is proud to announce the immediate availability of CakePHP 2.3.6[1]. 2.3.6 is a bugfix release for the 2.3 release branch. Since the release of 2.3.5 there have been 64 commits and 17 tickets resolved.

The CakePHP core team is proud to announce the immediate availability of CakePHP 2.3.6[1]. 2.3.6 is a bugfix release for the 2.3 release branch. Since the release of 2.3.5 there have been 64 commits and 17 tickets resolved. A short list of the changes you can expect is:

  • Datetime comparisons in CakeTime are more accurate now.
  • FormHelper now correctly marks fields with error classes on forms that save multiple records.
  • Controller::$modelClass is now set before components are initialized.
  • The file reading features of CakeEmail are now available outside the class.
  • Email line wrapping compatibility with japanese messages has been improved.
  • HtmlHelper::tag() now returns the content when $tag is false.
  • Mocked components are now enabled when using ControllerTestCase::testAction().
  • The type attribute can now be set when using HtmlHelper::script() and HtmlHelper::scriptBlock().
  • Passing an empty array does not reset SmtpTransport’s configuration anymore.
  • Xml parse errors with SimpleXmlElement now throw XmlException.
  • FormHelper now disables options in multi-select elements now.
  • TranslateBehavior now always uses $name instead of alias when updating/inserting rows.
  • Cookie expiry times in the distant future now work on 32bit systems.
  • FileEngine now clears groups with differing prefixes correctly.

Security disclosure

There were 3 recent security releases for CakePHP. With the goal of being open and transparent, and holding true to our previous commitments, below are more detailed descriptions of each problem.

Authentication forms

Authentication forms were vulnerable to query manipulation through the addition of additional POST data. Forms that were not also protected by SecurityComponent were vulnerable. If in a login form you had:

<input name=”data[User][username]” type=”text”><br /><input name=”data[User][password]” type=”password”>

Before submitting the form an attacker could add this HTML to the form:

<input name=”data[User][username][OR][id LIKE]” value=”1” type=”hidden”><input name=”data[User][username][OR][username LIKE]” value=”%admin%” type=”hidden”>

When the form was submitted, the $conditions used to log the user in would have the value of:

"OR" => array(
  "id like" => 1,
  "username like" => "%admin%"
)

This issue was introduced accidentally when adding support for blowfish authentication. The issue was resolved by treating any non- scalar conditions when authenticating users as a failure. This issue was corrected in this commit c327bd. Thanks to Magnus Andersson for the report and patch.

Pagination SQL injection

Through manipulation of the model alias used to sort a pagination URL, arbitrary SQL could be executed. This issue effected the 1.2, 1.3, and 2.x series of releases and was accidentally introduced 5 years ago. PaginatorComponent only validated the field name, but not the model alias. This meant that any SQL contained in the alias would be inlined as SQL. An example exploit URL would look like:

http://yourtest.com/users/index/sort:id%20LIMIT%2010;delete%20FROM%20%60contacts%60;.id

The above URL injects a DELETE query into the pagination request which would be executed without sanitization due to it being a sort key. This issue was fixed by ignoring the user data and using the known model alias in this commit 6017db. Thanks to ‘Ahmad’ for reporting the issue on lighthouse and helping the CakePHP team find a fix.

Cross site scripting through webroot

By manipulating the URL an attacker could generate an error page that allowed the execution of arbitrary javascript. The webroot property on the request object was incorrectly trusted as safe even though it contained user input. An example exploit could look like:

http://example.com/index.php/%3E%22%3E%3Cscript%3Ealert%28%27hehe%27%29;%3C/script%3E%3Clink%20href=%22HTTP/1.0%22%3C

The solution to this issue was to urlencode the user supplied webroot property when the request object is created. This makes generated URL’s safe to use in all normal contexts. The fix for this was applied in this commit db6dd1.

I’d like to thank the various people who reported the security issues and assisted in getting them fixed. I’d also like to thank all of the contributors who help keep CakePHP cooking. Without you there would be no CakePHP. Download a packaged release[2].

Links

published on Jun 10, 2013 12:00 AM

Read more

How to Cache CakePHP Db ACL Checks

How to Cache CakePHP Db ACL Checks

After enabling SQL query logging to Chrome Console I began noticing that queries against the ARO table appear running at 300 milliseconds or higher. This is data that doesn’t change often and is needed on every request so its a great candidate for caching. Unfortunately I couldn’t find any mechanism for caching DbAcl checks. Here is my solution.

CacheDbAcl

This is fairly straight forward. First create a new file at app/Lib/CacheDbAcl.php and copy and paste the code in (hyperlink) or see bottom of the article.

Next add the following configurations to app/Config/bootstrap.php: Configure::write(‘CacheDbAclConfig’,’default’); > Configure::write(‘CacheDbAclAro’,’User.UserGroup’);<br > > <p>Now add or edit the following in app Config/core.php: Configure::write(‘Acl.classname’, ‘CacheDbAcl’); ><br > Code Explained

The CacheDbAcl library works the exact same as the DbAcl library that is shipped with CakePHP 2.x. The only changes made are to the check() method. What it does:

  1. CacheDbAcl verifies caching is enabled. If it’s not enabled it just resumes normal operation.
  2. Reads in the name of the cache config you want to use, see CacheDbAclConfig.
  3. Checks what portion of the ARO you want to use as your cache key (more on this later), see CacheDbAclAro.
  4. Checks if an entry for the Aro, Aco, and Action exists in the cache. If not it performs its normal operations and then caches the results. Otherwise it just reads from the cache.

More on the CacheDbAclAro Setting

Since the ARO array passed into DbAcl::check can be quite different depending on your database structure and application requirements I allow you to set exactly which portion of the ARO you want to use as a unique cache key. If you want a cache created for each user, just don’t set this setting at all.

If you only want cache entries created for each group then use something similar to what I posted above. Maybe you have a special use-case and only want it using a very specific portion of the ARO as a key, this gives you that flexibility.

I went with User.UserGroup for this applicaton because our permissions are group based and I wanted to reduce the overall amount of cache entries created. When a group’s permissions are changed the modified field in the UserGroups model will naturally be updated so new cache entries will automatically be created and the old ones will eventually expire.

My original blog post

/**
 *
 * Licensed under The MIT License
 * For full copyright and license information, please see the LICENSE.txt
 * Redistributions of files must retain the above copyright notice.
 *
 * @copyright     Copyright (c) Chris Nizzardini
 * @link          http://cakephp.org CakePHP(tm) Project
 * @package       Cake.Controller.Component.Acl
 * @license       MIT License (http://www.opensource.org/licenses/mit-license.php)
 */
App::uses('AclInterface', 'Controller/Component/Acl');
App::uses('Hash', 'Utility');
App::uses('ClassRegistry', 'Utility');

/**
 * CacheDbAcl works the exact sabe as DbAcl expect that it will cache the results to using a cache config of your choosing:
 * - Configurations in bootstrap.php:
 * App::uses('CacheDbAcl', 'Lib');
 * Configure::write('CacheDbAclConfig','Name_of_Your_Cache_Config')
 * Configure::write('CacheDbAclAro','YourArrayKey.YourArray');
 *
 * - Configurations in core.php:
 * Configure::write('Acl.classname', 'CacheDbAcl');
 *
 * @package       Cake.Controller.Component.Acl
 */
class CacheDbAcl extends Object implements AclInterface {

/**
 * Constructor
 *
 */
    public function __construct() {
            parent::__construct();
            $this->Permission = ClassRegistry::init(array('class' => 'Permission', 'alias' => 'Permission'));
            $this->Aro = $this->Permission->Aro;
            $this->Aco = $this->Permission->Aco;
    }

/**
 * Initializes the containing component and sets the Aro/Aco objects to it.
 *
 * @param AclComponent $component
 * @return void
 */
    public function initialize(Component $component) {
            $component->Aro = $this->Aro;
            $component->Aco = $this->Aco;
    }

/**
 * Checks if the given $aro has access to action $action in $aco
 *
 * @param string $aro ARO The requesting object identifier.
 * @param string $aco ACO The controlled object identifier.
 * @param string $action Action (defaults to *)
 * @return boolean Success (true if ARO has access to action in ACO, false otherwise)
 * @link http://book.cakephp.org/2.0/en/core-libraries/components/access-control-lists.html#checking-permissions-the-acl-component
 */
    public function check($aro, $aco, $action = "*") {

        // if cache is disabled then default to normal operation
        if(Configure::read('Cache.disable') == true){
            return $this->Permission->check($aro, $aco, $action);
        }

        // read name of cache config for AclCache
        $cacheConfig = Configure::read('CacheDbAclConfig');
        // if not found then use default
        if(!$cacheConfig){
            $cacheConfig = 'default';
        }

        // check which portion of $aro to use for key
        $cacheAro = Configure::read('CacheDbAclAro');
        // if not set just serialze $aro
        if(!$cacheAro){
            $cacheKey = 'CacheDbAcl_'.md5(serialize($aro).$aco.$action);
        }
        // use custom portion of $aro
        else{
            $tmp = explode('.', $cacheAro);
            $aroTmp = false;
            foreach($tmp as $i){
                if($aroTmp == false){
                    $aroTmp = $aro[$i];
                }
                else{
                    $aroTmp = $aroTmp[$i];
                }
            }

            if(!isset($aroTmp) || empty($aroTmp)){
                $cacheKey = 'CacheDbAcl_'.md5(serialize($aro).$aco.$action);
            }
            else{
                $cacheKey = 'CacheDbAcl_'.md5(serialize($aroTmp).$aco.$action);
            }
        }

        // check for cache key in cache
        $check = Cache::read($cacheKey);

        // if key exists then return value
        if( $check !== false ){
            return $check;
        }
        // check database and write to cache
        else{
            $check = $this->Permission->check($aro, $aco, $action);
            Cache::write($cacheKey,$check,$cacheConfig);
        }

            return $check;
    }

/**
 * Allow $aro to have access to action $actions in $aco
 *
 * @param string $aro ARO The requesting object identifier.
 * @param string $aco ACO The controlled object identifier.
 * @param string $actions Action (defaults to *)
 * @param integer $value Value to indicate access type (1 to give access, -1 to deny, 0 to inherit)
 * @return boolean Success
 * @link http://book.cakephp.org/2.0/en/core-libraries/components/access-control-lists.html#assigning-permissions
 */
    public function allow($aro, $aco, $actions = "*", $value = 1) {
            return $this->Permission->allow($aro, $aco, $actions, $value);
    }

/**
 * Deny access for $aro to action $action in $aco
 *
 * @param string $aro ARO The requesting object identifier.
 * @param string $aco ACO The controlled object identifier.
 * @param string $action Action (defaults to *)
 * @return boolean Success
 * @link http://book.cakephp.org/2.0/en/core-libraries/components/access-control-lists.html#assigning-permissions
 */
    public function deny($aro, $aco, $action = "*") {
            return $this->allow($aro, $aco, $action, -1);
    }

/**
 * Let access for $aro to action $action in $aco be inherited
 *
 * @param string $aro ARO The requesting object identifier.
 * @param string $aco ACO The controlled object identifier.
 * @param string $action Action (defaults to *)
 * @return boolean Success
 */
    public function inherit($aro, $aco, $action = "*") {
            return $this->allow($aro, $aco, $action, 0);
    }

/**
 * Allow $aro to have access to action $actions in $aco
 *
 * @param string $aro ARO The requesting object identifier.
 * @param string $aco ACO The controlled object identifier.
 * @param string $action Action (defaults to *)
 * @return boolean Success
 * @see allow()
 */
    public function grant($aro, $aco, $action = "*") {
            return $this->allow($aro, $aco, $action);
    }

/**
 * Deny access for $aro to action $action in $aco
 *
 * @param string $aro ARO The requesting object identifier.
 * @param string $aco ACO The controlled object identifier.
 * @param string $action Action (defaults to *)
 * @return boolean Success
 * @see deny()
 */
    public function revoke($aro, $aco, $action = "*") {
            return $this->deny($aro, $aco, $action);
    }

/**
 * Get an array of access-control links between the given Aro and Aco
 *
 * @param string $aro ARO The requesting object identifier.
 * @param string $aco ACO The controlled object identifier.
 * @return array Indexed array with: 'aro', 'aco' and 'link'
 */
    public function getAclLink($aro, $aco) {
            return $this->Permission->getAclLink($aro, $aco);
    }

/**
 * Get the keys used in an ACO
 *
 * @param array $keys Permission model info
 * @return array ACO keys
 */
    protected function _getAcoKeys($keys) {
            return $this->Permission->getAcoKeys($keys);
    }

}

published on May 28, 2013 12:00 AM

Read more

CakePHP Modular Admin And Structured Content - Cloggy

CakePHP Modular Admin And Structured Content - Cloggy

Cloggy is a plugin for CakePHP for website administration. With Cloggy,all administration activities will be separated by modules. In addition to administration, Cloggy also provides a MySql database structure to facilitate developer / programmer to manage their contents.

Every website that we made, still need an administration area to manage their users,contents, and others. This is a mission of Cloggy. To help programmers to manage their admins.

Today i want to introduce my cakephp plugin to manage administration area. With Cloggy, all administration activities separated by modules, such as for blogging, users,search and others. You dont have to create your admin from scratch, just create a module that you need.

Inside Cloggy, module is a plugin extension (think about HMVC). You can create and manage your module without broke CakePHP convention standard, it means you don’t need to learn about module anymore.

Features:

  1. User module
  2. Search module
  3. Blog module
  4. Documentation module
  5. A nodes to manage your content

Beside an administration area, Cloggy also give a structured table content using node concept to help you to manage your content.

For detail information, just clone this plugin (documentation included!) :)

Cloggy still on active and agressive development until stable release (ver1.x). I need a feedback and your contribution to manage this plugin.

Github: Cloggy

published on May 18, 2013 12:00 AM

Read more

Security Fix: CakePHP 2.3.5 released

Security Fix: CakePHP 2.3.5 released

After conducting a security audit on our code we have patched a possible security risk in current CakePHP release.

CakePHP 2.3.5 has just been released to fix a critical issue with how the webroot property in CakeRequest is handled that could potentially lead to XSS attacks on certain pages. In the following days we will offer a full description of the vulnerability and how it can be exploited, after some reasonable time has passed for our users to upgrade.

A huge thanks to Florian Krämer for conducting a full security audit on the CakePHP code and Carl Sutton for report and providing a candidate patch.

In addition to the security fix 2.3.4 contains fixes for the following issues:

  • Increasing compatibility with old CentOS servers and the way they handle PHP regular expressions
  • Preventing pagiation limit from overflowing the max integer value
  • Making sure form ids generated in FormHelper::postLink() are actually unique
  • Fixed a bug in TextHelper auto link utility

We recommend all users of 2.x release series upgrade as soon as possible to the new release.

Links

published on May 11, 2013 12:00 AM

Read more

How to Log PHP Errors and SQL to Chrome Console in CakePHP

How to Log PHP Errors and SQL to Chrome Console in CakePHP

PHP errors can be a obnoxious when you’re developing an XHR heavy application with lots of JSON responses. The errors just aren’t very readable. So today I finally decided to implement ChromeLogger in our application here at work. This is one thing I’ve always missed since moving away from FireFox and its excellent plugin FirePHP.

First install ChromeLogger.

Setting up Chrome Logger and Error Handling

After installing the chrome plugin you’ll want to add the associated server-side library to app/Vendor/ChromePhp/ChromePhp.php. Next create a new file for handing errors in your CakePHP 2 project. Create a new class at app/Lib/AppError.php and add in the following code:

App::import('Vendor', 'ChromePhp/ChromePhp');
//in app/Lib/AppError.php
class AppError {
    public static function handleError($code, $description, $file = null, $line = null, $context = null) {
        ChromePhp::error('PHP Error Code '.$code.': '.$description.' '.$file.':'.$line);
    }
}

Next adjust your core.php and bootstrap.php files as follows.

In core.php

 'AppError::handleError',
    'level' => E_ALL & ~E_DEPRECATED,
    'trace' => true
));

In bootstrap.php

App::uses('AppError', 'Lib');

You’re done! For more information in AppError review the CakePHP2 documentation.

Setting up Chrome Logger For SQL Logging

Since most applications we write these days are XHR heavy the standard SQL Log CakePHP ships with is rendered useless. If you’re like me and obsess about optimizing queries then you’ll probably want all your queries logged to the Chrome Console. To add this functionality to your application open up your AppController and add the following to your afterFilter.

Now just set Configure::write(‘debug’,2) when you want to see queries exported to your Chrome Console. You’ll notice that I set all queries that took more than 100 milliseconds to appear as warnings and everything else as informational. Check out my blog for more CakePHP tutorials.

published on May 8, 2013 12:00 AM

Read more

Security Release - CakePHP 1.2.12, 1.3.16, 2.2.8 and 2.3.4

Security Release - CakePHP 1.2.12, 1.3.16, 2.2.8 and 2.3.4

If you are using CakePHP’s PaginatorComponent without whitelisted sort fields you should upgrade as soon as possible to prevent possible SQL injections.

CakePHP 1.2.12, 1.3.16, 2.2.8 and 2.3.4 have just been released to fix a critical issue with how pagination & PaginatorComponent handle sort criteria. When paginating without a sort column whitelist it was possible to execute arbitrary SQL by manipulating the sort conditions. In the following days we will offer a full description of the vulnerability and how it can be exploited, after some reasonable time has passed for our users to upgrade.

In addition to the security fix 2.3.4 contains fixes for the following issues:

  • Support for HTTP code 505 was added.
  • Router::currentRoute() returns false when there is no current route.
  • Writing to file cache after clearing a group now works as expected.
  • Asset URLS using fullBase are now generated correctly when not using URL re-writing.

There are no additional fixes outside the security fix in 2.2.8.

In addition to the security fix 1.3.16 contains fixes for the following issues:

  • Databases is now singularized correctly.
  • Saving translations with saveAll() now works better.
  • Oracle listSources() no longer reads from the global table namespace.
  • The cake console command now works on MacOS properly.
  • Mixing query[contain] and contain() now interact properly.

In addition to the security fix 1.2.12 contains fixes for the following issues:

  • umask is now set when creating cache files.
  • Boundaries for multipart email messages are now generated correctly.
  • Compatibility with PHP 5.4 has been improved.

We recommend all users of 1.2, 1.3, and 2.x release series upgrade as soon as possible to the new releases.

Links

published on Apr 28, 2013 12:00 AM

Read more

Security fix: CakePHP 2.3.3 available

Security fix: CakePHP 2.3.3 available

We have found a severe security issue that affects all applications running CakePHP version 2.3.0 and above that are using user authentication via forms with the AuthComponent without the Security component form tampering prevention.

The CakePHP core team pushed a maintenance release for 2.3 branch earlier than planned for the 2.3 branch of the framework. We have found a severe security issue that affects all applications running CakePHP version 2.3.0 and above that are using user authentication via forms with the AuthComponent without the Security component form tampering prevention.

If you have a login form and are using the AuthComponent without SecurityComponent field locking feature, you are strongly encouraged to upgrade to this version as soon as possible. In the following days we will offer a full description of the vulnerability and how it can be exploited, after some reasonable time has passed for our users to upgrade.

A huge thanks to Magnus Andersson for the report and patch.

CakePHP 2.3.3[1] is a bugfix release for the 2.3 release branch. Since the release of 2.3.2 there have been 31 commits and 8 tickets resolved. A short list of the changes you can expect is:

  • Fixed Vendor/bin/cake not working when installing CakePHP with composer.
  • Allowing behaviors’ beforeSave callback to change the datasource to be used for the actual save.
  • Fixing bug in FormHelper where the incorrect meridian would be selected for time fields.
  • Solved issues with models not being added when $uses = true.
  • Fixed condition parsing in mysql specific cases.
  • Added support for key => value cookies in HttpSocket.
  • Preventing “maxlength” attribute input element of type “number”.
  • Fixed incorrect timestamp values when using CakeTime::fromString()

Links

published on Apr 24, 2013 12:00 AM

Read more

Save HABTM data in a single simple format

Save HABTM data in a single simple format

Saving data from a HasAndBelongsToMany (HABTM) relationship with CakePHP is not the easiest part of using this framework. The main difficulty is that the format of HABTM data is not the same wether you want to associate existing records together (only update entries in the join table), or create new records and also associate them (create new records in the models table and in the join table).

When you wander out of CakePHP standards and automatically baked views and start saving custom data (using JavaScript for example), then you have to manually construct the data you send to your controllers and you have complete control over its format. You thus might want to be sure that your records and association will be saved in the right way wether you create new records or not. The simplest way is to settle for a format and always construct your data in the same fashion and let models handle the data (that is their job afterall).

The data format returned by a find() is the simplest to use: you easily have access to it in your views, and it is quite logical to use the same data format for find() and save(). You have an index for the main model of the find() and then an index for each associated Model. Multiple associated models like hasMany or hasAndBelongsToMany have subsequent subarrays for each associated entry. Building this type of array with existing data (we have an id) or new data (there is no id yet) is very simple. In the following example, Foo hasAndBelongsToMany Bar:

 `
array(
'Foo'=>array(
'id'=>'...',
...
),
'Bar'=>array(
(int)0=>array(
'id'=>'...',//ExistingBar,wehaveitsid
'name'=>'...'//Thenamemayhavebeenmodified
),
(int)1=>array(
'name'=>'...'//ThisBarwillbecreated
)
)
)
`

Then with a simple snippet of code, you can overload the saveAssociated() function to save each instance of Bar: create new ones (those without an id) and update existing ones. Then call the parent saveAssociated() function from the library (you rarely want to entirely overload functions from the library) with a nicely formated association array (the one from our first case) to update the entries in the join table. Copy the following code in your AppModel.php and the trick is done!

 `
publicfunctionsaveAssociated($data=null,$options=array()){
foreach($dataas$alias=>$modelData){
if(!empty($this->hasAndBelongsToMany[$alias])){
$habtm=array();
$Model=ClassRegistry::init($this->hasAndBelongsToMany[$alias]['className']);
foreach($modelDataas$modelDatum){
if(empty($modelDatum['id'])){
$Model->create();
}
$Model->save($modelDatum);
$habtm[]=empty($modelDatum['id'])?$Model->getInsertID():$modelDatum['id'];
}
$data[$alias]=array($alias=>$habtm);
}
}
returnparent::saveAssociated($data,$options);
}
`

Read more....

published on Apr 19, 2013 12:00 AM

Read more

CakePHP 2.3.2 released

CakePHP 2.3.2 released

The CakePHP core team is proud to announce the immediate availability of CakePHP 2.3.2[1]. 2.3.2 is a bugfix release for the 2.3 release branch.

The CakePHP core team is proud to announce the immediate availability of CakePHP 2.3.2[1]. 2.3.2 is a bugfix release for the 2.3 release branch. Since the release of 2.3.1 there have been 60 commits and 17 tickets resolved. A short list of the changes you can expect is:

  • API documentation has been improved for a number of methods.
  • Imported fixtures without a primary key no longer trigger notice errors.
  • FormHelper::year() supports dates outside of 1901-2038 on all platforms now.
  • SchemaShell should more reliabily detect schema changes when dumping schema.
  • CakeTestCase::$dropTables is no longer ignored in some situations.
  • PHPUnit can now be included as a dependency via composer.
  • Using a Datasource from a non-datasource package will now raise an exception. This prevents hard to debug errors when you accidentally use a model/other class as a datasource.
  • FormHelper now correctly selects the hour at midnight with a 12hr format. As well as correctly handling the meridian.
  • Validation::uuid() is now more strict.
  • Canadian postal code validation is now more strict.
  • Default values for SqlServer are now correctly handled for nullable columns.
  • The object cache used by App is only loaded as needed now instead of on every request.
  • HtmlHelper::script() and HtmlHelper::css() now handle the fullBase option.
  • JS, CSS, IMAGES constants are now conditionally defined by CakePHP making it possible to override them in your application.
  • FormHelper now better handles the disabled attribute when defined as an array value instead of an array key.

A huge thanks to all involved in terms of both contributions through commits, tickets, documentation edits, and those whom have otherwise contributed to the framework. Without you there would be no CakePHP. Download a packaged release[2].

Links

[1] http://cakephp.org/changelogs/2.3.2

[2] http://github.com/cakephp/cakephp/tags

published on Apr 7, 2013 12:00 AM

Read more

User Management Plugin with Twitter Bootstrap for cakephp 2.x version 2.2

User Management Plugin with Twitter Bootstrap for cakephp 2.x version 2.2

I have released a new version(2.2) of my plugin for user management. Demo at http://umpremium.ektanjali.com. This plugin has total 85 features. This plugin is Basic need of your website. Basically It gives you all features which you need on starting your website or a project in cakephp 2.x framework.

This plugin has total 85 features.

It is very helpful for Beginners because of following features-

Clean code with coding standards Proper documentations Newbie will learn- a. How to write code in Cakephp? b. How to use CSRF/XSS protection in cakephp c. How to use SSL/HTTPS in cakephp for whole site as well as only some pages. d. How to use Ajax Pagination in cakephp. e. How to use Ajax Form Validations with File/Image in cakephp.

and may more.

For all features, Beginners please have a look on http://developers.ektanjali.com/docs/umpremium/version2.2/beginners.html Experts will also learn many other things. For all features http://umpremium.ektanjali.com You can start your project or a website in few minutes with this plugin because this plugin has all things which you can think in starting of your project.

The main features are- Twitter Bootstrap framework added Login with Facebook, Twitter, Linkedin, Four Square, Gmail, Yahoo. All Configurations are database driven. No need to touch php code for config setting. No need to hard code your site URL any where. View Online users and guest and admin can take many action on online users. SSL support for selected pages or whole site. Most of the things are Ajax driven. Mailer system

I cannot describe all features here so please have a look on demo at http://umpremium.ektanjali.com here you can find all features of this plugin.

published on Apr 6, 2013 12:00 AM

Read more

Petit four, the quick and easy online CakePHP baking tool

Petit four, the quick and easy online CakePHP baking tool

Petit four is an online application that allows you to design the models of your applications and then automatically generate a SQL database and the base files for CakePHP: models, controllers and view directories.

In our Web agency we have been glad to use CakePHP for almost two years as it has really helped us speed up our projects.

However from time to time there are still some tasks that feel a bit slow or tiresome, like creating the basics files to start a project, or add models on the fly during the development process. The console baking tool can be useful and has been improved over the years but has many limitations and you don’t always want to start it each time you add a new model to your application in order to bake a model, a generic controller and generic view files that you won’t necessary use as such.

That is why we developed a tool that allows us to speed up our modeling process by easily creating the models, their attributes and their relations and generating at the same time the SQL file ready to be imported in a database, and the CakePHP basic files needed to build an application on it.

Mind that this is only a beta version with a narrow set of functionalities. We focused on the first layer that is needed for any kind of MVC application: a database and models files. We throwed in the creation of controllers and view directories, because they can be useful, but as they are not always needed, we left them empty for the moment.

Bake your Cakes online.

We designed a tool that would be useful for us, and we hope it will also benefit the community and we plan on continuously improving it. We already have a few improvements in mind, mainly to bring it to the same level as the console bake for code generation:

  • Editing the validation rules for model attributes
  • Optionally generating the basics controller actions and views
  • Attaching behaviors to a model

Read more instructions and more improvements that we have in mind.

Please comment this article, or send us suggestions for this tool on the pâtisserie or by email at contact@keensoftware.com .

published on Mar 27, 2013 12:00 AM

Read more

Create your own Pinterest App with Engaged - Made with CakePHP

Create your own Pinterest App with Engaged - Made with CakePHP

Engaged is an open source software that lets you create your own Pinterest like applications. With Engaged - You can share your interests (of course) - You can create hierarchical interest categories - You can change app’s look & feel using settings - You can add new users thanks to Authake plugin

Engaged

LIVE DEMO: http://www.mtkocak.net/engaged DOWNLOAD: https://github.com/mtkocak/engaged

Engaged is an open source software that lets you create your own Pinterest like applications. With Engaged - You can share your interests (of course) - You can create hierarchical interest categories - You can change app’s look & feel using settings - You can add new users thanks to Authake plugin

Features B0x1A1

  • A Flexible user interface that you can almost change everything. Background images, Header & Pin colors can be changed using color picker.
  • Easy to use control panel
  • Hierarchical Categories like a tree
  • Multiple language support (For now English & Turkish)
  • Authake User Management https://github.com/mtkocak/authake

Requirements B0x1A1

  • PHP installed webserver 5.3+
  • MySQL database

Installation B0x1A1

  1. Copy the all files to your server. For general xampp or mamp there is a htdocs folder. Create a folder named ‘engaged’ and copy all files there. If you install to your local webserver, at the end you should access to you Engaged app from http://127.0.0.1/engaged. Don’t try to access it now. Installation is not finished yet :)
  2. You have to first change permissions of App/tmp folder and it’s subfolders. If you receive App/tmp/cache/persistent error, just create that folder. Also change the permissions for App/webroot/img folders. (Unix: Chmod 777) (Windows: I don’t know)
  3. On your MySQL database, create a database called engaged. Import engaged.sql file in the db folder.
  4. Change App/Config/database.php like:
public $default = array(
    'datasource' => 'Database/Mysql',
    'persistent' => false,
    'host' => 'YOURHOSTNAME',
    'login' => 'YOURUSERNAME',
    'password' => 'DATABASEPASSWORD',
    'database' => 'engaged',
    'prefix' => '',
    //'encoding' => 'utf8',
);

public $authake = array(
    'datasource' => 'Database/Mysql',
    'persistent' => false,
    'host' => 'YOURHOSTNAME',
    'login' => 'YOURUSERNAME',
    'password' => 'DATABASEPASSWORD',
    'database' => 'engaged',
    'prefix' => '',
    //'encoding' => 'utf8',
);
  1. After you change the database config, you can access http://127.0.0.1/engaged. A wild installation form will appear. Simply change that as you want and you are ready!

Author B0x1A1 Mutlu Tevfik Kocak (a.k.a Midori)`http://www.mtkocak.net`_

For questions and everything: mtkocak@gmail.com

published on Mar 24, 2013 12:00 AM

Read more

CakeFest 2013 - Vote for the location

CakeFest 2013 - Vote for the location

CakeFest 2013 will be happening later in the year. We need your help to decide the location!

CakeFest 2013 has a number of large communities around the world. Two of our largest, the USA and Japan, are up for selection for the next CakePHP conference. We’d like to empower you, the user, to input your own selection and help us decide where to take the next CakeFest conference.

Visit the CakeFest Website for more information and to put forward your vote!

published on Mar 20, 2013 12:00 AM

Read more

CakePHP product management 2.x

CakePHP product management 2.x

WidShop is a CakePHP based product management plugin where user can add/edit and manager offers. ><br > Demo at http://www.widahead.com/cakephp-product-plugin > <br > Contact @ widahead@gmail.com General Features: > 1. Add Edit Category > 2. Create Update Services/product and assign on category > 3. Create Update offer on the services > 4. Select Currency type based on country<br > 5. Paypal Do Direct payment method > 6. Back Order functionality (Offer if expired, book then we send mail to get confirmation to get the offer. when we activate after.)<br > 7. Add counter on product/service listing page and view page > 8. Dynamic Categories<br > 9. Side Cart Block with product list > <br > > Additional Features:<br > 1. Admin prefix Urls > 2. SEO Enabled URL<br > 3. Unique URL for all products > 4. Resize Images<br > 5. Create single offer or multiple offer based on single or multiple services > 6. Create day hours bases deals > 7. Multiple service with in a single offer like a bundle of service in a single offer<br >

published on Mar 12, 2013 12:00 AM

Read more

Rails Migration in Your CakePHP application.

Rails Migration in Your CakePHP application.

Manage your database like a PRO :) ================================= Today I wrote something that may help you in your cakephp application. Managing database is a pain. If you ever have used rails. Switching between rails and cakephp I always missed the migration thingy. If you use composer.phar then its fairly simple to use this code. And I believe application nowdays are not bound to one programming language. So your next application can be a hybrid application that uses Ruby and PHP :) ..... You find the code in github. https://github.com/rajibahmed/rake-db-migrator

Rails Less Migration =====================

Today I was wanted to use rails goodness inside of my php project. So, I searched online found a solution somewhere. Fixed it up for any project to use using composer.

I assume you are using tools listed below and know how to use command line.

  • POSIX OS
  • Ruby the programming Language
  • Rake the build tool written in Ruby
  • Activerecord gem, defaults with Rails !!!!

To enable it, add this dependency to your composer.json file:

"rajibahmed/rake-db-migrator": "dev"

Or Find it here rajibahmed/rake-db-migrator

Step 1: To enable it in your application you need to create few directories from you terminal :)

$ mkdir -p db/migrate
$ mkdir config

Note 1: You do not need to create the structure if you already have it. Note 2: I have provided a demo database.yml configuration file copy over to config folder.

Step 2: symlink my rake file to root of you project.

$ ln -s vendor/rajibahmed/rake-db-migrator/Rakefile .

Step 3: You are done !!

So now you can use this rake file to create and migrate you configured database. Available Rake tasks are,

rake db:create    # Create the database from config/database.yml for the current DATABASE_ENV
 rake db:drop      # Drops the database for the current DATABASE_ENV
 rake db:generate  # Generate migration files
 rake db:migrate   # Migrate the database (options: VERSION=x, VERBOSE=false).
 rake db:rollback  # Rolls the schema back to the previous version (specify steps w/ STEP=n).
 rake db:version   # Retrieves the current schema version number

Now, Running

rake db:generate

Will create a template file that you can use as a reference point for writing your first migration.

Note[IMPORTANT] : Class name in a migration file must match the file naming convention. ie.

CreateUser < ActiveRecord::Migration
 # file name should be timestramp_create_user.rb
 end

You are good to go !!! This is a few hours effort. If you want to extend it please fork it or send me emails.

LICENSE: Do whatever you want with it. I don’t want money from you and can’t be held responsible any fu*k ups. Good luck !!! Simple isn’t it.

published on Mar 8, 2013 12:00 AM

Read more

CakePHP 2.3.1 released

CakePHP 2.3.1 released

The CakePHP core team is proud to announce the immediate availability of CakePHP 2.3.1. 2.3.1 is a bugfix release for the 2.3 release branch.

The CakePHP core team is proud to announce the immediate availability of CakePHP 2.3.1[1]. 2.3.1 is a bugfix release for the 2.3 release branch. Since the release of 2.3.0 there have been 70 commits and 20 tickets resolved. A short list of the changes you can expect is:

  • The ServerShell now correctly handles plugin and theme assets.
  • FormHelper::inputs() now correctly handles plugin models.
  • Backwards compatibility for HABTM checkboxes has been improved.
  • Schema generation works better with SQLServer now.
  • Baking models better detects has and belongs to many associations.
  • Security::rijndael() now correctly generates random iv values. It will continue to decrypt values encrypted with a fixed iv. This improves security of encrypted values, by preventing dictionary attacks on the key/value.
  • Altering tables with Postgres properly renames fields now.
  • Regular expression operators are better supported in Postgres.
  • Fatal errors now display when gzip encoding is enabled.
  • Model whitelists are restored when a save() fails due to no data, when a model has no created/updated fields.
  • Validation::$errors is no longer populated with booleans, this prevents memory consumption issues in longer running scripts.

In addition to the release of 2.3.1, the API docs have been updated and replaced with a system based on apigen. The new API docs fix a number of issues with the old docs and provides an easy way for you to create local API docs.

A huge thanks to all involved in terms of both contributions through commits, tickets, documentation edits, and those whom have otherwise contributed to the framework. Without you there would be no CakePHP. Download a packaged release[2].

Links

[1] http://cakephp.org/changelogs/2.3.1

[2] http://github.com/cakephp/cakephp/tags

published on Mar 3, 2013 12:00 AM

Read more

CAKEPHP-DATATABLE - A component for working with jQuery DataTables

CAKEPHP-DATATABLE - A component for working with jQuery DataTables

CakePHP-Datables provides server-side interoperability between CakePHP 2.x and the jQuery DataTables plugin.

Features:

  • Takes paginated data and converts into json response compatible with datatables
  • Accepts dataTables ORDER BY requests
  • Accepts dataTables WHERE conditions
  • Accepts dataTables pagination
  • Works LinkableBehavior and to a lesser extent Containable

Dependancies: - PHP 5.x - CakePHP 2.x - LinkableBehavior is recommended but not required - and ofcourse the latest version of DataTabes.

Installation

You can either clone the project, download the project, or just copy & paste DataTableComponent.php into your projects Controller/Component directory

Demo http://cakephpdatatables.cnizz.com/

See https://github.com/cnizzdotcom/cakephp-datatable for full documentation or http://blog.cnizz.com/2013/01/31/cakephp-datatables-a-component-for-interoperability-between-cakephp-and-jquery-datatables/

published on Feb 18, 2013 12:00 AM

Read more

CakePHP 2.2.7 released

CakePHP 2.2.7 released

The CakePHP core team is happy to announce the immediate availability of CakePHP 2.2.7.

CakePHP 2.2.7 released

The CakePHP core team is happy to announce the immediate availability of CakePHP 2.2.7[1]. This is a bugfix release for the 2.2.x release branch. After the release of 2.2.6 last week a regression was reported for how select element and selected values were being handled. This issue is now resolved, and 2.2.7 should be the final 2.2.x release unless additional regressions are reported.

A big thanks to those involved in finding and fixing this issue. Download a packaged release [2]

Links

published on Feb 2, 2013 12:00 AM

Read more

CakePHP 2.3.0 is out!

CakePHP 2.3.0 is out!

The CakePHP core team is proud to announce the immediate availability of CakePHP 2.3.0 and 2.2.6[1]. There have been a few small improvements and fixes since the release of 2.3.0-RC2.

The CakePHP core team is proud to announce the immediate availability of CakePHP 2.3.0 and 2.2.6[1]. There have been a few small improvements and fixes since the release of 2.3.0-RC2.

CakePHP 2.3 is now marked as stable

2.3.0 is a new version that is completely compatible with its 2.2.5 predecessor. If you get excited to upgrade your projects right away after reading this announcement, make sure you read the migration guide in the book [2], as there are a few changes that your application might require

This is a quick review of the changes that made it in this new iteration.

Authorization

AuthComponent received some love, it is now much easier to implement stateless authorization mechanisms that will respond with appropriate error codes instead of redirecting on missing access rights. The new ` AuthComponent::$unauthorizedRedirect` property was added to control this behavior at runtime and it can be set to false or to an URL as needed.

For improved security, we have added a new Blowfish adapter that will hash your passwords using blowfish/bcrypt.

Additionally, we have deprecated ` AuthComponent::redirect()` in favor of ` AuthComponent::redirectUrl` to better reflect what the method is doing.

Paginator

If you want to use a custom find method in your pagination calls, it is now easier. Just set the ` findType` key in the Paginator settings array and profit!

We have also decided to return a NotFoundException error in case any user tries to access a page of out range instead of serving an inexistent one or the first, which was the previous behavior.

Now setting the ‘limit’ manually in the Paginator settings array to a value bigger than maxLimit will actually bring maxLimit to the same value, no need to repeat yourself.

Custom view classes

Don’t like the built-in implementation for content type views? Need to extend them somehow? That is easier than ever! Just set the view class name using ` RequestHandlerComponent::viewClassMap()` or set the map directly in the settings array for the RequestHandlerComponent.

We <3 PHP 5.4

Yeah, we still support 5.2. But, it did not prevent us from releasing a cool shell command for creating an standalone php server for quick development. Just start it with ` Console/cakeserver`

Configuring your app

Configuration engines are now capable of storing their internal state to the format they understand. ` ConfigReaderInterface::dump()` was added and the correspondent implementation for the IniReader engine. This is useful if you need to persist dynamically generated configuration or if you want to implement a custom configuration engine that stores in a database.

A common complaint about CakePlugin::loadAll() was that it did not check whether the bootstrap files in plugins actually existed or not. This made it difficult for applications like a CMS to load all extensions in one go. While we still believe each plugin should be loaded with the correct settings, we have added a new ` ignoreMissing` key in the plugin configuration array. ` CakePlugin::loadAll(array(‘ro utes’=>true,’bootstrap’=>true,’ignoreMissing’=>true))` will load all plugins and not yell at you if one of the routes.php or bootstrap.php files is missing.

Networking and email

Just as you can read the posted data using dot notation with ` request->data(‘key’)`, you can now do the same with the querystring, by using the method ` request->query(‘key’)`

After some thought, we decided to deprecate MediaView. All its code lives now in CakeResponse::file(), this makes it a one-liner to send files directly to the browser either by streaming it or making it an download.

We added support for TLS connections in CakeSocket, this made it possible to send emails over SMTP + TLS protocols. Also, it is now possible to set the Content-Disposition header for attachments sent with CakeEmail by using the ` contentDisposition` option

As a minor, but important change, HttpResponse was deprecated and all its code resides in the new class HttpSocketResponse.

Views and helpers

The view class received some love once again, continuing our efforts since 2.1. One of the changes is to make ` View::fetch()` have a default text in case the requested block is empty. Also, ` View::prepend` handy method was added to prepend text to any existing block. In case you were interested in executing some code only if a block already existed, then the new ` View::startIfEmpty()` might be what you were looking for.

If you had a case where you could not know in advance whether an element file existed or not, 2.3 is now for you. We have introduced ` View::elementExists()` and added the ` ignoreMissing` option to ` View::element()` to suppress the missing element errors.

Another simple yet important change: our default layout uses HTML5 as doctype. We did this because now FormHelper will add the ` required` attribute to your fields.

FormHelper got even more intelligent, it can now select the correct input type for telephone and email fields. Also, it is now possible to to use any HTTP verb in ` FormHelper::postLink()`

PaginatorHelper got a few new and very much anticipated features:

  • ` PaginatorHelper::numbers()` now has a new option currentTag to allow specifying extra tag for wrapping current page number.
  • For ` PaginatorHelper::prev()` and ` PaginatorHelper::next()` it is now possible to set the tag option to false to disable the wrapper. Also a new option disabledTag has been added for these two methods.

Finally, helpers got a $settings property, that will be set with any array specified from the controller.

Caching

  • File Engine is now the default caching engine, this solves quite a few problems with people not having APC installed or forgetting to change the cache prefix when having multiple apps on the same server
  • It is finally possible to have different full page caches, for example a different cache per subdomain. This is achieved with the new viewPrefix setting in the cache configuration. ` Configure::write(‘Cache.viewPrefix’,‘YOURPREFIX’);`

Models

IMPORTANT: ` Model::find(‘first’)` will now return an empty array when no records are found. Make sure you update your tests!

  • Added support for bigint data types and MySQL FULLTEXT indexes.
  • ` Validation::fileSize()` was added.

When testing models, or controllers, you can now use ` CakeTestCase::getMockForModel()` for quickly generating model mocks that will have the correct alias, table name and be correctly registered in the ClassRegistry.

Since 2.3.0-RC2 the following bit were changed

  • Renamed AuthComponent::redirect() to AuthComponent::redirectUrl().
  • Added “tel” and “email” input type guessing.
  • Controller::_getViewObject() method for constructing the View object when rendering
  • Don’t set “required” attribute for checkboxes (unless explicitly specified).
  • Removed Security.level from core.php
  • Display exact PDO error on default homepage
  • Allow AuthComponent::$unauthorizedRedirect to be an url.
  • Added feature to ignore include errors for CakePlugin
  • Allowed ` between` option for radio buttons to be an array of strings

See the changelog for a full list of changes in 2.3.0[3]

Changes for the 2.2.x branch

  • Make sure sessions are started before destroying them.
  • Consistently inflecting theme names, this means that every theme should start with an uppercase as the other folders
  • Add OK or Successful HTTP codes 200-206 to HttpResponse::isOK(). Fixes #3531
  • Only bake HABTM associations for tables that exist.
  • Add support for –admin to bake controller all.
  • Fixing the way to follow redirects when fetching XML files.
  • Fix Token fields being added to GET forms.
  • Allow afterFind() to fully remove an associated record. By returning array() or unsetting the 0’th result an afterFind callback should be able to fully remove data from the results.

The changelog[4] has the full list of changes in 2.2.5

A huge thanks to all involved in terms of both contributions through commits, tickets, documentation edits, and those whom have otherwise contributed to the framework. Without you there would be no CakePHP.

Download a packaged release [1]

Links

published on Jan 28, 2013 12:00 AM

Read more

Why that solutions?

Internationalization with static and dynamic content, routing and switching =========

Many times, when I prepare a new website I always think how to solve better internationalization. Mainly how resolve displaying dynamic content in the event that this has not been translated into the selected language, how to make search friendly links (called nice urls, slugs) in the database, how to solve the problem of routing these links and how to perform switching and keeping language. In last web project I was prepared application without Cookies and Session, but I only by switching parameter in the address (URL).

Why that solutions?

Because Session and Cookies works perfectly when We haven’t translated links by magic function from Gettext ( __(); ).

In many tutorials setting language is inside Controller (mainly AppControler or Component). This doesn’t work when We use translate content in Router ( Router::connect(); ). Sometimes tutorials resolved problem by set language and refresh page (by $this->redirect(); ). I don’t like that!

Routing

I would like URL like these:

/ // home page for default language
/en // home page for english
/pl // home page for polish
/de // home page for germany
/register // register action (for e.g. UsersController) for default language
/pl/rejestracja // register action for polish
/de/anmeldung // register action for germans

And I thinking shouldn’t work links like these:

/pl/register // polish language for translated action name
/en/anmeldung // like above
…

Why? Because in my opinion there is no place for mixing links (mainly for SEO).

My solutions is setting language before app starting (AppController) and this is most ugly part in my article, latter I wrote why.

Let’s start coding!

bootstap.php (app/Config):

define('DEFAULT_LANGUAGE', 'en').

Configure::write('Config.languages', array(
    'en' => 'English version',
    'pl' => 'Język polski',
    'de' => 'Deutsch Version'));

In first line we define constant with 2-letter code for default language, which is English. Next prepare array with codes and description languages for own app and save it in configuration.

routes.php (app/Config):

$language = substr(Router::url(''), 0, 2); // check that it works properly (sometimes You must trip part of url, for e.g. folder names)
$languages = array_keys(Configure::read('Config.languages'));

if(!in_array($language, array_diff($languages, array(DEFAULT_LANGUAGE)))) {
    $language = DEFAULT_LANGUAGE;
    $schema = '';
} else {
    $schema = '/:language';
}

Configure::write('Config.language', $language);

/* PagesController */
Router::connect('/', array(
    'controller' => 'pages',
    'action' => 'display',
    'home'));
Router::connect('/:language', array(
    'controller' => 'pages',
    'action' => 'display',
    'home'), array(
            'language' => implode('|', $languages)));

/* UsersController */
Router::connect($schema .'/'. __('register', true), array(
    'controller' => 'users',
    'action' => 'register'), array(
            'persist' => array(
                    'language')));

Yeah, in first line is most ugly code from all codes. This get first 2 letters from url for checking what is code represent language inside configurations ‘Config.languages’. Next prepare schema for using in routing schemas and write selected language to Config.language . In this code I was prepare 3 routing schemas for home page with default language and with selected language and last for registration page.

Note: How prepare app to using static translated content, using Poedit app It has been well described in the book “CakePHP 1.3 Application Development Cookbook” by Mariano Iglesias (Yeap, the book was translated to polish!).

There is no different between 1.3 and 2.x.

I use magic parameter ‘persist’ for routing. It’s works for adding language params for $this->Html->links(); when the schema using /:language . More info on Router API.

AppHelper.php (app/Views/Helpers):

function url($url = null, $full = false) {
    if($this->params['language'] == DEFAULT_LANGUAGE) {
            unset($this->params['language']);
    }

    return parent::url($url, $full);
}

I must rewrite url() method because I want using language parameter from configuration. I unset language params when it is default, because we have duplicate content (by 2 urls: /register and /en/register).

When I rewrite url() method and using persist in routing schemas these two things work perfectly together!

default.ctp (app/Views/Layouts/):

Now we test own app with codes below:

foreach(Configure::read('Config.languages') as $code => $language) { // show links for translated version
    echo $this->Html->link($language, array(
            'controller' => 'pages',
            'action' => 'display',
            'home',
            'language' => $code)) .' ';
}

echo $this->Html->link(__('register', true), array( // show link to registartion page
    'controller' => 'users',
    'action' => 'register'));

And static, routing and switching all done.

Dynamic content

For dynamic conent Cake setting $locale variable by default in own app from configuration ( Config.language ). How setting this variable by hand is described on Saving in another language.

But if We want display translate article from database and this article isn’t translated I want view oryginal version. How do this?

AppController.php (app/Controller):

Put code below to beforeFilter(); .

if(Configure::read('Config.language') !== DEFAULT_LANGUAGE) {
    $this->{$this->modelClass}->locale = array(Configure::read('Config.language'), DEFAULT_LANGUAGE);
} else {
    $this->{$this->modelClass}->locale = DEFAULT_LANGUAGE;
}

This try get translated version (first array param) or oryginal version (second param).

How add, edit and translate content? I think the best way is adding content in only default language, but if You want translate content and save it, You must switch language and go to edit page.

This is magic! Whem we are on edit page and there is no language param in url, we save it in default language, but when there is language param in url, we save it in selected language.

Don’t forget to prepare i18n database table and Your model for translated fields.

That’s all! I waiting on question and comments! Tested on 2.2.5 version.

Sorry, but I still learn english.

kicaj blog.kdev.pl

published on Jan 27, 2013 12:00 AM

Read more

Backup your SQL database with BackupMe console application

Backup your SQL database with BackupMe console application

BackupMe is a console script to create SQL databases dump backups for CakePHP applications.

A shell application to create SQL databases dump backups (Tables only!).

Download: https://bitbucket.org/mmahgoub/cakephp-backupme/

This script is based upon the one written by David Walsh and published on his blog on August 18, 2008 http://davidwalsh.name/backup-mysql-database-php

Many thanks to him!

Instructions

  1. Download the repo and put it in your app/ folder.
  2. Open up your CakePHP shell and run the command “cake backup” (You can use cron jobs)

This script backup all of your tables by default but you can select specific tables by uncommenting

//$tables = array('orders', 'users', 'profiles');

and filling your own table names.

  • Notice: This application uses ProgressBar Task written by Matt Curry. If you want to use it should be in vendors/shells/tasks directory otherwise please comment the lines which contains:
$this->ProgressBar->start($num_fields);

$this->ProgressBar->next();

I don’t know why you wanna do that! That progress bar is awesome! Thanks Matt!

Arguments

  1. Database configuration, default is “default”.
  2. Rows per query (less rows = less ram usage but more running time) default is 0 which means all rows.
  3. Absolute path for the directory to save your backup, it will be created automatically if not found, default is app/db-backups/yyyy-mm- dd

Additional possible features

  1. Upload backup using FTP.

published on Jan 25, 2013 12:00 AM

Read more

CakePHP 2.3.0-RC2 and 2.2.5 released

CakePHP 2.3.0-RC2 and 2.2.5 released

The CakePHP core team is proud to announce the immediate availability of CakePHP 2.3.0-RC2 and 2.2.5[1]. There have been a few small improvementsand fixes since the release of 2.3.0-RC1. If there are no serious issues reported 2.3.0 stable should be released within a few weeks.

The CakePHP core team is proud to announce the immediate availability of CakePHP 2.3.0-RC2 and 2.2.5[1]. There have been a few small improvementsand fixes since the release of 2.3.0-RC1. If there are no serious issues reported 2.3.0 stable should be released within a few weeks.

Changes since 2.3.0-RC1

Since the release fo 2.3.0-RC1 a few new improvements have been added. In addition, all changes in 2.2.5 are also present in 2.3.0-RC2. The new improvments to 2.3.0-RC2 are:

  • Using an unknown cache engine results in exceptions being thrown.
  • Improved support for HTML5 attributes.
  • PaginatorComponent now throws exceptions when users request page numbers that are out of range. This is instead of displaying duplicate content from the last page in the series.
  • PaginatorHelper::prev() and PaginatorHelper::next() now support the ‘disabledTag’ option. This option can be used to set the wrapping tag when these controls are not available.
  • An .editorconfig file was added.
  • The default doctype is now HTML5
  • FormHelper sets the required attribute on inputs based on detected validation rules.
  • Support for php.ini style numbers was added to CakeNumber::fromReadableSize()
  • Generated text for pagination buttons in related models are now easier to read.
  • FormHelper::postLink() sets the target attribute on the form element instead of the a element.

See the changelog[2] for a full list of changes in 2.3.0-RC2

Changes in 2.2.5

2.2.5 is a bugfix/maintenance release for the 2.2.x release branch. There have been 40 commits & 19 issues fixed since 2.2.4. Some of the notable fixes are:

  • Fields using the || operator are now quoted correctly.
  • Stack traces on error pages now highlight code excerpts correctly.
  • File inputs no longer include the value attribute. This fixes HTML validation with HTML5 doctypes.
  • ConsoleOptionParser now correctly handles options with the value of ‘0’.
  • Mysql datasource now correctly handles indexes with a length value.
  • The 5th argument is no longer passed to mail() when safe_mode is active.
  • Email bodies are now wrapped at 998 instead of 78 characters. This fixes issues where HTML content would be spliced.
  • TreeBehavior and nested deletes work as expected now.
  • Infinite loops when rendering error 500 pages with extensions declared by Router::parseExtensions() have been fixed.
  • Requests to the SecurityComponent’s blackholeCallback are now blackholed. This was an issue when using a public unprefixed method as the SecurityComponent’s blackhole callback.
  • Theme names are now consistently camelcased in both helper assets & view files.
  • FormHelper::radio() now treats boolean values as equivalents to 1 and 0 respectively.
  • Hash::expand() no longer loops infinitely in PHP5.2 when expanding deeply nested structures.

The changelog[3] has the full list of changes in 2.2.5

A huge thanks to all involved in terms of both contributions through commits, tickets, documentation edits, and those whom have otherwise contributed to the framework. Without you there would be no CakePHP. Download a packaged release [1]

Links

published on Jan 9, 2013 12:00 AM

Read more

CakePHP Community 2012

CakePHP Community 2012

2012 was the year CakePHP turned 7 years old, maintaining it’s reign as one of the major PHP frameworks.

CakePHP: a framework built and shaped by the community

2012 was an important year for CakePHP. Versions 2.1 and 2.2 of the framework were released, and work on the future 3.0 version began. We had over 7 million combined visits to the CakePHP sites, with over half of those being new visitors. More than 17 million page views were registered for the CookBook alone, with http://book.cakephp.org being the most popular location of all.

CakeFest 2012 saw some excellent guest speakers, with people from across the globe who couldn’t make it tuning in and watching the event via streaming video. We also got a lot of feedback this year from the community, prompting us to create official Facebook, Google and LinkedIn groups for CakePHP, to help people stay in touch with the latest news and discussions.

We also gathered some interesting demographics to share with you all, for the people who were most active and influential with CakePHP in 2012.

The top 5 communities, based on country, were the following:

  1. United States
  2. Brazil
  3. India
  4. France
  5. Japan

They were followed by Germany, United Kingdom, Canada and Spain, with the number one city based upon engagement world wide being Tokyo, Japan.

Additionally, the top 5 languages were the following:

  1. English (en-us/gb)
  2. Portuguese (pt-br)
  3. French (fr)
  4. Spanish (es)
  5. Japanese (ja)

It was also interesting to see that 45% of the community who engaged with us were aged between 25-34, followed by 30% from 18-24, and the remaining over 34 or under 18. The gender difference was around 10% female and 90% male.

And finally, based upon browser usage, Chrome came out on top, with 46% of all visits to the CakePHP site. It was followed by Firefox (34%), Safari (9%) and IE (6%).

Of course, these statistics are just numbers. The reality is that every single person who contributes to CakePHP, no matter where you are, or which language you speak, male of female, you are important. That’s why we thank each and every one of you for making CakePHP what it is today - a framework created by the community! Thank you.

published on Dec 28, 2012 12:00 AM

Read more

Display Tree Index with OL and LI

Display Tree Index with OL and LI

As i prefer using the original helpers and behaviors, i also use it for my Trees. In this article i’d like to clearify how we can display a tree using unsorted lists or even tables. Expecting you created your database tables consulting Trees, you should be able to use the following code in the controller of your category model:

<?php
class CategoriesController extends AppController {
    public function index() {

            $categories = $this->Category->find('threaded', array(
                    'order' => array('Category.lft'))
            );
            $this->set('categories', $categories);

    }
}
?>

This returns an array with all categories in a nested structure.

To parse, or let me say, to display this array without having trouble to use UL- or OL-Tag’s, or even tables, let me introduce recursive functions to you:

<?php
function RecursiveCategories($array) {

    if (count($array)) {
            echo "\n<ul>\n";
        foreach ($array as $vals) {

                    echo "<li id=\"".$vals['Category']['id']."\">".$vals['Category']['name'];
                    if (count($vals['children'])) {
                            RecursiveCategories($vals['children']);
                    }
                    echo "</li>\n";
        }
            echo "</ul>\n";
    }
} ?>

This function returns a list of ul’ and li’s for each category and it’s children. If a child has got children, the function just calls itself for them and returns a further ul. Now just print the result in your view:

<?= RecursiveCategories($categories) ?>

Should be easy to add your arrows for moving categories up or down, or even delete. You just have to put them into the li.

published on Dec 20, 2012 12:00 AM

Read more

CakePHP 2.3.0-RC1 and 2.2.4 are finally here

CakePHP 2.3.0-RC1 and 2.2.4 are finally here

Following the release of 2.3.0-beta around one month ago, we are excited to announce that 2.3 is very close to be marked as stable!

The CakePHP core team is proud to announce the immediate availability of CakePHP 2.3.0-RC1 and 2.2.4[1]. 2.3.0-RC1 marks the freezing of 2.3.0 API and it is jsut a matter of a few weeks to mark it as stable if no bugs are found in current codebase.

Changes since 2.3.0-beta

  • Added ConfigReaderInterface::dump() and made all readers’ dump() method support ‘Plugin.keyname’ format for keys
  • Made View trigger notice by default if elements are missing and added elementExists() method
  • Added Helper::$settings to match other objects like components and behaviors
  • You no longer have to specify ‘maxLimit’ when setting ‘limit’ greater than default ‘maxLimit’ when configuring pagination settings.
  • Added type hinting to Model::validator()
  • prev() and next() methods of PaginatorHelper now possible to place the ‘tag’ option to ‘false’ to disable the wrapping element.
  • Calling Form->input() with ‘errorMessage’=>false should trigger field error, but not render error message (HTML element).
  • New options in HtmlHelper::getCrumbList() to make it compatible with Twitter Bootstrap, Zurb foundation or other CSS frameworks.
  • Added CakeTestCase::getMockForModel convenience method.
  • Implemented SSL peer verification in HttpSocket.
  • Added context() to CakeSocket.
  • Renamed HttpResponse to HttpSocketResponse. HttpResponse will continue to exist for backwards compatibility.
  • Using bytecode sequence for unicode ellipsis in String::trim().
  • When using XmlView, you can configure the top level element name by setting the _rootNode view variable.
  • Added warning to home.ctp when DebugKit is not installed and added a list of official plugins to home.ctp
  • Added View::startIfEmpty()
  • Added foreignKey to whitelist in saveAssociated()
  • RedisEngine: authenticate connection if ‘password’ is set

Changes in 2.2.4

2.2.4 is a bugfix/maintenance release for the 2.2.x release branch. These are some of the changes included:

  • Update TLD validation to accept gTLD variations
  • Fixed sorting empty data with Hash & Set.
  • Fixed multi-model validators with deep & atomic validation error nesting
  • Fixed exceptions being thrown in beforeFilter breaking error pages.
  • Using HttpSocket to get proper exceptions when trying to load XML from remote servers to fix warnings from file_get_contents() in Xml::build()
  • Send charset=UTF-8 if Content-Type is JSON.
  • Added query logging to DboSource::insertMulti().
  • Fixed contain rule parsig in authentication adapters
  • Fixed required validation rule
  • Removed Inflector::slug() replacement from Ä to A
  • Fixed issue with Model::saveAssociated() and TranslateBehavior
  • Only setting $request->data with PUT/DELETE when it can be decoded.
  • Improved “required” field detection.
  • Made Model::find(‘first’) always return an array.
  • Fixed issue where the incorrect meridian would be selected in FormHelper::dateTime()
  • Fixed issue where createSchema() would omit primary keys sometimes.
  • Fixed saveAssociated() with validate=first, atomic=false
  • Showing the last 200 queries instead of the first 200 in SQL log.
  • Fixed 0’th index file not being copied to $_FILES.
  • Fixed autoLinkUrls so it re-capture query strings.
  • Allow saving new records with pre specified primary key value with treebehavior.
  • Fix find(‘count’) with ‘group’ when result has only one group.

A huge thanks to all involved in terms of both contributions through commits, tickets, documentation edits, and those whom have otherwise contributed to the framework. Without you there would be no CakePHP. Download a packaged release [3]

Links

published on Dec 2, 2012 12:00 AM

Read more

Versioned DbMigrations

Versioned DbMigrations

Need more control than only just being able to update your database schema via CakePHP’s Migration shell ? Well, this is a dirty quick solution for actually versioning your database ! And a great tool to let all developers on your CakePHP project to keep their respective databases up-to-date. You can choose to either do this auto-magically, or use the plugin’s GUI to go back and forth between versions at will. The best part is that it utilizes CakePHP’s “Model” layer to it’s fullest, hence you can practically do anything when you jump from version to version.

CakePHP: Versioned Db Migrations Plugin for CakePHP 2.0

Installation

Install this plugin following the simple steps below:

  1. Copy this plugin in a directory called “DbMigrations” inside your app/Plugin directory.
  2. Now load the plugin in your application’s bootstrap file (typical location: app/Config/bootstrap.php) by pasting this line:
CakePlugin::load('DbMigrations');
  1. After this, take a look at DbMigrations/Config/config.php. Here you will find two setting:
table => 'db_migrations'
and sanityCheck => true

These settings are as simple as they sound. The "table" is the name of the table the DbMigrations plugin is going to use.
You can change it to your liking.
The second setting: "sanityCheck", when turned to "TRUE" lets DbMigrations check if the table specified in the "table"
property exists. If not, it simply creates it so that you won't have to do a thing :)
  1. After following the above steps, there are two ways in which you can keep your databases up-to-date.
4.1. You can simply paste this line "ClassRegistry::init('DbMigrations.Migration')->upgrade(true)" in your AppController::beforeFilter().
     Following this way, whenever your you hit a page, the AppController::beforeFilter() will be executed, hence, the DbMigrations plugin
     will update your database to the latest version if it's not already.

4.2. OR you can go to the plugin's GUI, http://your_website_url/db_migrations/migrations and choose the revision you'd like
     your database to be updgraded or downgraded to.

NOTE: I won’t recommend using both 4.1 or 4.2 at the same time.

And you’re all set ! - Also, I would always advise to keep this kind of auto-upgrades for environments like Test and Development. It won’t be good practice at all to use this for production. Fits the dev environment best though.

How this works B0x1A6 So to get started, after when you have followed the installation steps make a folder “Migrations” in your “app” directory. You will find a “Migrations” folder already in the “DbMigrations” directory. That is the default folder. You’d be better off keeping your files organized in a folder in your app dir for better organization. (In future versions I can have that folder name and path configurable too).

A sample file list in the “Migrations” folder would look like this:

001_initial_db_dump.php
002_users_table_add_deleted_field.php
003_create_samples_table.php
004_changes_for_issue_336.php

There are two parts to the files you create. As you can see, the name of the files that is prefixed by a version number. These version numbers need to be unique as it’s going to be an incremental updates for the database.

Now to look inside a sample file. For, say, the second file, “002_users_table_add_deleted_field.php”, the contents would be simply:

class DbMigration_2 extends DbMigrationsAppModel {

    public function up() {
        $sql = "ALTER TABLE  `users` ADD  `deleted` TINYINT( 1 ) NOT NULL";
        $this->query($sql);
    }

    public function down() {
        $sql = "ALTER TABLE `users` DROP `deleted`";
        $this->query($sql);
    }
}

After making all the changes (following steps in the installation) and making these files, if you are following step 4.1 to update your database, then when you run your application for the first time, it will run all these files, hence pushing all changes in your database.

If you notice, you’ll see that all “DbMigration_{$revisionNumber}” classes are instances of the CakePHP Model. Hence you can use CakePHP’s model layer to it’s full potential !

If at any point in time, say you need to downgrade your changes to a specific revision number, assuming 2 for this explanation. All you need to do is execute this statement at any suitable place in your code:

ClassRegistry::init('DbMigrations.Migration')->downgrade(2);

This will rollback all changes till revision 2. Which means it will drop the table “samples” (you should code the drop statement in the downgrade() function of DbMigration_3 class).

If you wish to make your database up-to-date again, then just issuing the upgrade() statement, it will re-create the samples table and push all changes for issue 336. It won’t execute changes for files 001 and 002.

OR alternatively, you can follow step 4.2.

Important Notes

You will need to be carefuly to name your DbMigration_X classes, that “X” should correspond to the revision number that is prepended to every migration file.

There are no checks implemented at this point. No exceptions if you screw up. So you will really need to be careful in coding the up() and down() functions for your DbMigration_X classes.

You can also even insert data into tables and issue update statements.

Hope this plugin makes your life easier and makes development fast !

Find this plugin on my GitHub profile: https://github.com/SayB/DbMigrations

published on Nov 24, 2012 12:00 AM

Read more

Tagcloud Helper Cakephp 2

Tagcloud Helper Cakephp 2

Adjustable Helper to build a word/tag cloud.

<?php

/*
 *  @author: syl-via@go2.pl & Suhail Doshi
 */

class TagcloudHelper extends Helper {
    /* font sizes */

    var $minSize = 10;
    var $maxSize = 50;

    /* colors */
    var $red = 110;
    var $green = 105;
    var $blue = 255;

    /* div sizes */
    var $div_size = 400;

    /* show frequencies */
    var $show_frequencies = false;

    /*  @author: syl-via
     *  @param array $tags Tags to build the cloud on. Ex array('name'=>20,'tag2'=>32)
     *  @param (optional) int  $div_size The size of the div for the words
     *  @param (optional) int  $minSize  Minimum size of the font
     *  @param (optional) int  $maxSize  Maximum size of the font
     *  @param (optional) int  $red
     *  @param (optional) int  $green
     *  @param (optional) int  $blue
     *
     *  returns string div with span of tags.
     */

    public function word_cloud($tags, $div_size = null, $show_frequencies = null, $minSize = null, $maxSize = null, $red = null, $green = null, $blue = null) {
        if ($show_frequencies != null)
            $this->show_frequencies = $show_frequencies;
        if ($div_size != null)
            $this->div_size = $div_size;
        if ($minSize != null)
            $this->minSize = $minSize;
        if ($maxSize != null)
            $this->maxSize = $maxSize;
        if ($red != null)
            $this->red = $red;
        if ($green != null)
            $this->green = $green;
        if ($blue != null)
            $this->blue = $blue;

        $data = $this->formulateTagCloud($tags);
        $data = $this->shuffleTags($data);

        /* Build cloud */
        $cloud = "<div style=\"width: {$this->div_size}px\">";
        foreach ($data as $word => $options) {
            $cloud .= "<span style=\"font-size: {$options['size']}px; color: {$options['color']};\">";
            $cloud .= str_replace(" ", " ", $word);
            if ($this->show_frequencies) {
                $cloud .= " <small>({$options['score']})</samll> ";
            }
            $cloud .= "</span> ";
        }
        $cloud .= "</div>";
        return $cloud;
    }

    /*
     *  @author: Suhail Doshi
     */

    public function formulateTagCloud($dataSet) {
        asort($dataSet); // Sort array accordingly.
        // Retrieve extreme score values for normalization
        $minimumScore = intval(current($dataSet));
        $maximumScore = intval(end($dataSet));

        // Populate new data array, with score value and size.
        foreach ($dataSet as $tagName => $score) {
            $size = $this->getPercentSize($maximumScore, $minimumScore, $score);
            $color = $this->getColor($maximumScore, $score);
            $data[$tagName] = array('score' => $score, 'size' => $size, 'color' => $color);
        }

        return $data;
    }

    /*  @author: syl-via
     *  @param int $maximumScore Maximum score value in array.
     *  @param int $currentValue Current score value for given item.
     *
     *  returns string Hex(ex: #000012) value of RGB.
     */

    public function getColor($maximumScore, $currentValue) {
        $b = floor($this->blue * ($currentValue / $maximumScore));
        return '#' . sprintf('%02s', dechex($this->red)) . sprintf('%02s', dechex($this->green)) . sprintf('%02s', dechex($b));
    }

    /*  @author: Suhail Doshi
     *  @param int $maxValue Maximum score value in array.
     *  @param int $minValue Minimum score value in array.
     *  @param int $currentValue Current score value for given item.
     *  @param int [$minSize] Minimum font-size.
     *  @param int [$maxSize] Maximum font-size.
     *
     *  returns int percentage for current tag.
     */

    private function getPercentSize($maximumScore, $minimumScore, $currentValue) {
        if ($minimumScore < 1)
            $minimumScore = 1;
        $spread = $maximumScore - $minimumScore;
        if ($spread == 0)
            $spread = 1;
        // determine the font-size increment, this is the increase per tag quantity (times used)
        $step = ($this->maxSize - $this->minSize) / $spread;
        // Determine size based on current value and step-size.
        $size = $this->minSize + (($currentValue - $minimumScore) * $step);
        return $size;
    }

    /*  @author: Suhail Doshi
     *  @param array $tags An array of tags (takes an associative array)
     *
     *  returns shuffled array of tags for randomness.
     */

    public function shuffleTags($tags) {
        while (count($tags) > 0) {
            $val = array_rand($tags);
            $new_arr[$val] = $tags[$val];
            unset($tags[$val]);
        }
        if (isset($new_arr))
            return $new_arr;
    }

}
?>

published on Nov 14, 2012 12:00 AM

Read more

Authake for CakePHP 2.2.3 is finally out!

Authake for CakePHP 2.2.3 is finally out!

The most easy to use authorization plugin is finally out with tremendous changes.

To dovnload & contribute:https://github.com/mtkocak/authake

For install instructions and feedback, please go to Authake home page: http://www.mtkocak.net/?p=507

http://www.mtkocak.net/wp-content/uploads/2012/11/authake.png

Newest features are:

  1. Totally new look & feel. New interface using twitter bootstrap library<br/>
  2. Generated schema file to use cache schema create
  3. Total adaptation to CakePHP 2.2.3
  4. Totally new Dashboard
  5. Gravatar Support
  6. Better alerts
  7. Beautiful navigation and breadcrumbs
  8. html5shiv support for older browsers
  9. Dropdown lists for commands
  10. Help file with regex information
  11. Settings page (needs some effort)
  12. Better readme files with markdowns

Further changes are here for your contribution:

  • sha1 security
  • long id’s
  • settings save issue
  • For questions and issues: Mutlu Tevfik Kocak mtkocak(at) gmail.com

published on Nov 12, 2012 12:00 AM

Read more

CakePHP 2.3.0-beta released

CakePHP 2.3.0-beta released

This release contains several new features that improves CakePHP performance, security and ease of use.

The CakePHP core team is proud to announce the immediate availability of CakePHP 2.3.0-beta[1]. This release contains several new features that improves CakePHP performance, security and ease of use. When it is done, this new version is intended to be a replacement for the 2.2.x branch and will be completely backwards compatible. A migration guide is provided in the book [2] and we encourage you to read it if you are upgrading from an older version.

A short list of the changes you can expect are:

Constants

  • An application can now easily define CACHE and LOGS, as they are conditionally defined by CakePHP now

Caching

  • FileEngine is always the default cache engine. In the past a number of people have had difficulty setting up and deploying APC correctly both in cli + web. Using files should make setting up CakePHP simpler for new developers.

Components

AuthComponent

  • A new authenticate adapter has been added to support blowfish/bcrypt hashed passwords. You can now use Blowfish in your $authenticate array to allow bcrypt passwords to be used.
  • Allow throwing exception instead of redirecting upon unauthorized access attempt, this is controlled by a new option in AuthComponent. This is useful when you want to block access to users with stateless authentication

PaginatorComponent

  • PaginatorComponent now supports the findType option. This can be used to specify what find method you want used for pagination. This is a bit easier to manage and set than the 0’th index.

SecurityComponent

  • SecurityComponent now supports the unlockedActions option. This can be used to disable all security checks for any actions listed in this option.

RequestHandlerComponent

  • RequestHandlerComponent::viewClassMap() has been added, which is used to map a content type to view class name. You can add $settings[‘viewClassMap’] for automatically setting the correct viewClass based on extension/content type.

CookieComponent

  • CookieComponent::check() was added. This method works the same as CakeSession::check() does.

Console

  • The server shell was added. You can use this to start the PHP5.4 web-server for your CakePHP application.
  • Baking a new project now sets the application’s cache prefix to the name of the application.
  • Adding symlink resolution to app/Console/cake

I18n

  • nld is now the default locale for Dutch as specified by ISO 639-3 and dut its alias. The locale folders have to be adjusted accordingly (from /Locale/dut/ to /Locale/nld/).
  • Albanian is now sqi, Basque is now eus, Chinese is now zho, Tibetan is now bod, Czech is now ces, Farsi is now fas, French is now fra, Icelandic is now isl, Macedonian is now mkd, Malaysian is now msa, Romanian is now ron, Serbian is now srp and Slovak is now slk. The corresponding locale folders have to be adjusted, as well.
  • Corrected the usage of domain translation for a few internal strings in validation rules.
  • Now all translation functions can be overridden by declaring the function first.

Configure

  • Configure::check() was added. This method works the same as CakeSession::check() does.

Exceptions

  • CakeBaseException was added, which all core Exceptions now extend.
  • The base exception class also introduces the responseHeader() method which can be called on created Exception instances to add headers for the response, as Exception responses don’t reuse any response instances.

Model

  • Support for the biginteger type was added to all core datasources, and fixtures.
  • Support for FULLTEXT indexes was added for the MySQL driver.
  • Model::find(‘list’) now sets the recursive based on the max containment depth or recursive value. When find(‘list’) is used with ContainableBehavior.
  • Added DboSource::resetSequence(). This allows datasources to reset sequence values in tables. This is useful for datasources like Postgres, and makes using fixtures much easier.
  • DboSource::getLog() will now show the last 200 queries instead of the first 200.

Validation

  • Missing validation methods will always trigger errors now instead of only in development mode.
  • Added CakeNumber::fromReadableSize() and Validation::filesize()

Network

  • Added enableCrypto() method to CakeSocket class
  • TLS/SSL support was added for SMTP connections.

CakeRequest

  • CakeRequest::onlyAllow() was added.
  • CakeRequest::query() was added to access variables in the query string using dot notation.

CakeResponse

  • CakeResponse::file() was added. This deprecates MediaView.
  • When instantiating a CakeResponse, it will by default set its charset to App.encoding

CakeEmail

  • The contentDisposition option was added to CakeEmail::attachments(). This allows you to disable the Content-Disposition header added to attached files.

Router

  • Support for tel:, sms: were added to Router::url().
  • Enable dot notation for passing plugin for routeClass parameter
  • Routes are loaded as late as possible. As a consequence - routes will also work by default in the cli.

View

  • MediaView is deprecated, and you can use new features in CakeResponse to achieve the same results.
  • Serialization in Json and Xml views has been moved to _serialize()
  • beforeRender and afterRender callbacks are now being called in Json and Xml views when using a view templates.
  • View::fetch() now has a $default argument. This argument can be used to provide a default value should a block be empty.
  • View::prepend() has been added to allow prepending content to existing block.

Helpers

FormHelper

  • FormHelper::select() now accepts a list of values in the disabled attribute. Combined with ‘multiple’ => ‘checkbox’, this allows you to provide a list of values you want disabled.
  • FormHelper::postLink() now accepts a method key. This allows you to create link forms using HTTP methods other than POST.
  • Fixed disabled attribute for multiple checkboxes
  • Hidden divs created by FormHelper can now be customized by using the hiddenblock template in HtmlHelper::$tags property
  • Improved “required” field detection.

TextHelper

  • TextHelper::tail() was added to truncate text starting from the end.
  • ending option in TextHelper::truncate() is deprecated in favor of ellipsis

PaginatorHelper

  • PaginatorHelper::numbers() now has a new option currentTag to allow specifying extra tag for wrapping current page number.

CakeNumber

  • CakeNumber::fromReadableSize() was added.
  • CakeNumber::formatDelta() was added.
  • CakeNumber::defaultCurrency() was added.

Folder

  • Folder::copy() and Folder::move() now support the ability to merge the target and source directories in addition to skip/overwrite.

String

  • String::tail() was added to truncate text starting from the end. ending in String::truncate() is deprecated in favor of ellipsis

Debugger

  • Debugger::exportVar() now outputs private and protected properties in PHP >= 5.3.0.

Security

  • Support for bcrypt was added. See the Security::hash() documentation for more information on how to use bcrypt.

A huge thanks to all involved in terms of both contributions through commits, tickets, documentation edits, and those whom have otherwise contributed to the framework. Without you there would be no CakePHP. Download a packaged release [3]

Links

published on Oct 28, 2012 12:00 AM

Read more

Cake Bake Templates for Twitter Bootstrap

Cake Bake Templates for Twitter Bootstrap

Templates for baking BootStrap compatible views in CakePHP.

Templates for baking BootStrap compatible views in CakePHP

Put this folder in your appConsoleTemplatedefault and copy the actions and classes folder from the CakeConsoleTemplatesdefault folder, too.

Now when you bake that app you will get custom views that make a reasonably decent Bootstrap app.

Use the default.ctp layout file as a good starting point.

https://github.com/vz28bh/CakePHP-Bootstrap-Templates

published on Oct 12, 2012 12:00 AM

Read more

Twitter Bootstrap Plugin for CakePHP

Twitter Bootstrap Plugin for CakePHP

Twitter Bootstrap (http://twitter.github.com/bootstrap/) is a powerful front-end framework. I’d really love to use this for several projects and pages. Now I have created a simple plugin to use the power of Twitter Bootstrap easier inside CakePHP.

With Twitter Bootstrap you get a fast and powerful front-end framework that makes it easier to design pretty cool websites. In my eyes this is a must for every web-designer and developer.

My plugin can be found on GitHub under https://github.com/visionred/BootstrapCake

It comes across with a easy shell for loading the framework files, creating compatible layouts and a strong view helper. A documentation is also available.

So just take a look at it and enjoy the power of Twitter Bootstrap.

If you have any questions, ideas or bugs send me a message or report an issue on GitHub.

Cheers, Florian Nitschmann

published on Oct 11, 2012 12:00 AM

Read more

Jquery Validation Helper

Jquery Validation Helper

JQuery Validation Helper reduces the duplication of the Cake model configuration in Javascript.

I was implementing JQuery Validate plugin for the first time and quickly realized that it required adding all the same validation rules that are in the Cake models. Since that seemed to violate DRY, I came up with a helper that scans the model validation rules and creates the equivalent validation rules for the JQuery plugin and stores them as a string in the dialog class item.

https://github.com/vz28bh/CakePHP-JqueryValidationHelper

First, include JQuery and the Validate plugin in your layout. There is also an ‘additional-methods’ file that defines a few extra validation rules. You also need the metadata plugin to decode the string with the validation rules.

echo $this->Html->script('jquery-1.7.2.min');
echo $this->Html->script('jquery.validate.min');
echo $this->Html->script('additional-methods.js');
echo $this->Html->script('jquery.metadata');

Then add the helper in your controller

public $helpers = array( 'Html','Form', 'Js' => array('Jquery'), 'JqueryValidation' );

When you create a dialog you need to provide a special class that is used in the javascript to detect which forms to validate:

echo $this->Form->create('Order', array('class' => 'jquery-validation'));

Then for each element that you want to validate, use the helper function for the input:

echo $this->JqueryValidation->input('serial', $options);

This function just calls the Form->input after modifying the options array.

Here is the code for the helper. This is still a work in progress so there are a couple of Cake validation rules that I don’t have working, so feel free to update or add new rules. The good news is the basic validation rules are covered with very little additional work. Note that it only works for multiple rules per field format.

App::uses('AppHelper', 'View/Helper');

class JqueryValidationHelper extends AppHelper {

  public $helpers = array('Form');

  #-- Map to replace constants with jquery and class info
  #-- Pass as $options['jquery-validate']
  public $options = array(
      'map' => array(
          '__formSelector__' => '.jquery-validation',
          '__errorElement__' => 'span',
          '__errorClass__' => 'help-block',
          '__hilightClass__' => 'form-error',
          '__closestSelector__' => '.control-group',
          '__closestErrorClass__' => 'error'
      )
  );
  private $validation_messages = array();
  private $js = "
    $(document).ready(function(){
      $('__formSelector__').each( function(index) {
        $(this).validate({
          'errorElement': '__errorElement__',
          'errorClass': '__errorClass__',
          'highlight': function(element,errorClass) {
            $(element)
            .siblings().remove();
            $(element)
            .addClass('__hilightClass__')
            .closest('__closestSelector__').addClass('__closestErrorClass__');
          },
          'unhighlight': function(element,errorClass) {
            $(element)
            .removeClass('__hilightClass__')
            .closest('__closestSelector__').removeClass('__closestErrorClass__')
          },
        });
      });
    });";

  /**
   * input
   *
   * Routine to mimic form helper in order to get needed info.
   *
   * @param type $fieldName
   * @param type $options
   */
  public function input($fieldName, $options = array()) {

    $map = $this->options['map'];
    if (isset($options['jquery-validate'])) {
      if (isset($options['jquery-validate']['map'])) {
        $map = array_merge($map, $options['jquery-validate']['map']);
      }
      unset($options['jquery-validate']);
    }
    $model = $this->Form->defaultModel;
    $meta = $this->meta($model, $fieldName);
    if (!empty($options['class'])) {
      $options['class'] .= ' {' . $meta . '}';
    } else {
      $options['class'] = $meta;
    }
    $response = '';
    #-- Inlcude the js if needed
    if (!empty($this->js)) {
      $formatted_js = strtr($this->js, $map);
      $response .= "<script type=\"text/javascript\">" . $formatted_js . "</script>";
      $this->js = '';
    }
    $response .= $this->Form->input($fieldName, $options);
    return $response;
  }

  /**
   * meta
   *
   * Returns a meta string to be added to the class of a dialog input
   *
   * @param type $model
   * @param type $field
   * @return string
   */
  public function meta($model, $field) {
    $model_object = new $model();
    foreach ($model_object->validate as $validateField => $validateItem) {
      CakeLog::write('debug', 'JqueryValidate->meta: validateField=' . $validateField);
      if ($field == $validateField) {
        if (is_array($validateItem)) {
          CakeLog::write('debug', 'JqueryValidate->meta: validateItem=' . print_r($validateItem, true));
          foreach ($validateItem as $validateName => $validateParams) {
            if (!empty($validateParams['rule'])) {
              $rule = $validateParams['rule'];
              CakeLog::write('debug', 'JqueryValidate->meta: $rule=' . print_r($rule, true));

              if (is_array($rule)) {
                $msg = $rule[0];
              } else {
                $msg = $rule;
              }
              if (!empty($validateParams['message'])) {
                $msg = $validateParams['message'];
              }
              $ruleName = $rule[0];
              CakeLog::write('debug', 'JqueryValidate->meta: ruleName=' . $ruleName);
              $methodName = 'jquery_validate_' . $ruleName;
              if (method_exists($this, $methodName)) {
                $meta[] = $this->$methodName($model, $field, $rule, $msg);
                CakeLog::write('debug', 'JqueryValidate->meta: $meta=' . $meta);
              } else {
                CakeLog::write('debug', 'JqueryValidate->meta: function $ruleName not found');
              }
            }
          }
        }
      }
    }
    if (is_array($meta)) {
      $messages_str = '';
      if (is_array($this->validation_messages)) {
        $messages_str = implode($this->validation_messages, ', ');
      }
      $meta_str = implode($meta, ', ');
      return "'rules': {" . $meta_str . ", 'messages': { " . $messages_str . "}}";
    } else {
      return '';
    }
  }
/**
 *  Various functions to convert a CakePHP validation to a Jquery Validate meta tag
 */
  private function jquery_validate_alphaNumeric($model, $field, $params, $msg) {
    CakeLog::write('debug', 'JqueryValidate->date: params=' . print_r($params, true));
    $this->validation_messages[] = "date: '" . $msg . "'";
    return "'date': true";
  }

  private function jquery_validate_between($model, $field, $params, $msg) {
    CakeLog::write('debug', 'JqueryValidate->between: params=' . print_r($params, true));
    $this->validation_messages[] = "between: '" . $msg . "'";
    return "'min': " . $params[1] . ", 'max': " . $params[2];
  }

  private function jquery_validate_blank($model, $field, $params, $msg) {
    CakeLog::write('debug', 'JqueryValidate->blank: params=' . print_r($params, true));
    $this->validation_messages[] = "rangelength: '" . $msg . "'";
    return "'rangelength': [0, 0]";
  }

  private function jquery_validate_boolean($model, $field, $params, $msg) {
    CakeLog::write('debug', 'JqueryValidate->boolean: params=' . print_r($params, true));
    return '';
    $this->validation_messages[] = "boolean: '" . $msg . "'";
    return "'boolean': true";
  }

  private function jquery_validate_cc($model, $field, $params, $msg) {
    CakeLog::write('debug', 'JqueryValidate->cc: params=' . print_r($params, true));
    $this->validation_messages[] = "creditcard: '" . $msg . "'";
    return "'creditcard': true";
  }

  private function jquery_validate_comparison($model, $field, $params, $msg) {
    CakeLog::write('debug', 'JqueryValidate->comparison: params=' . print_r($params, true));
    $op = $params[1];
    $value = $params[2];
    switch ($op) {
      case '>':
        $value++;
        $this->validation_messages[] = "'min': '" . $msg . "'";
        return "'min': " . $value;
        break;
      case '>=':
        $this->validation_messages[] = "'min': '" . $msg . "'";
        return "'min': " . $value;
        break;
      case '<':
        $value--;
        $this->validation_messages[] = "'max': '" . $msg . "'";
        return "'max': " . $value;
        break;
      case '<=':
        $this->validation_messages[] = "'max': '" . $msg . "'";
        return "'max': " . $value;
        break;
      case '!=':
        $value++;
        $this->validation_messages[] = "'min': '" . $msg . "'";
        $str = "'min': " . $value;
        $value = $value - 2;
        $this->validation_messages[] = "'max': '" . $msg . "'";
        return $str . ", 'max': " . $value;
        break;
      default:
        return '';
    }
  }

  private function jquery_validate_date($model, $field, $params, $msg) {
    CakeLog::write('debug', 'JqueryValidate->date: params=' . print_r($params, true));
    $this->validation_messages[] = "date: '" . $msg . "'";
    return "'date': true";
  }

  private function jquery_validate_datetime($model, $field, $params, $msg) {
    CakeLog::write('debug', 'JqueryValidate->datetime: params=' . print_r($params, true));
    return '';
    $this->validation_messages[] = "datetime: '" . $msg . "'";
    return "'datetime': true";
  }

  private function jquery_validate_decimal($model, $field, $params, $msg) {
    CakeLog::write('debug', 'JqueryValidate->decimal: params=' . print_r($params, true));
    $this->validation_messages[] = "number: '" . $msg . "'";
    return "'number': true";
  }

  private function jquery_validate_email($model, $field, $params, $msg) {
    CakeLog::write('debug', 'JqueryValidate->email: params=' . print_r($params, true));
    $this->validation_messages[] = "email: '" . $msg . "'";
    return "'email': true";
  }

  private function jquery_validate_equalTo($model, $field, $params, $msg) {
    CakeLog::write('debug', 'JqueryValidate->equalTo: params=' . print_r($params, true));
    $this->validation_messages[] = "equalTo: '" . $msg . "'";
    return "'equalTo': '" . Inflector::camelize($model) . Inflector::camelize($params[1]) . "'";
  }

  private function jquery_validate_extension($model, $field, $params, $msg) {
    CakeLog::write('debug', 'JqueryValidate->extension: params=' . print_r($params, true));
    $this->validation_messages[] = "accept: '" . $msg . "'";
    return "'accept': '" . implode($params[1], "|") . "'";
  }

  private function jquery_validate_inList($model, $field, $params, $msg) {
    CakeLog::write('debug', 'JqueryValidate->inList: params=' . print_r($params, true));
    return '';
    $this->validation_messages[] = "inList: '" . $msg . "'";
    return "'inList': true";
  }

  private function jquery_validate_ip($model, $field, $params, $msg) {
    CakeLog::write('debug', 'JqueryValidate->ip: params=' . print_r($params, true));
    $this->validation_messages[] = "ipv4: '" . $msg . "'";
    return "'ipv4': true";
  }

  private function jquery_validate_luhn($model, $field, $params, $msg) {
    CakeLog::write('debug', 'JqueryValidate->luhn: params=' . print_r($params, true));
    return '';
    $this->validation_messages[] = "luhn: '" . $msg . "'";
    return "'luhn': true";
  }

  private function jquery_validate_maxLength($model, $field, $params, $msg) {
    CakeLog::write('debug', 'JqueryValidate->maxLength: params=' . print_r($params, true));
    $this->validation_messages[] = "'maxlength': '" . $msg . "'";
    return "'maxlength': " . $params[1];
  }

  private function jquery_validate_minLength($model, $field, $params, $msg) {
    CakeLog::write('debug', 'JqueryValidate->minLength: params=' . print_r($params, true));
    $this->validation_messages[] = "'minlength': '" . $msg . "'";
    return "'minlength': " . $params[1];
  }

  private function jquery_validate_money($model, $field, $params, $msg) {
    CakeLog::write('debug', 'JqueryValidate->money: params=' . print_r($params, true));
    return '';
    $this->validation_messages[] = "money: '" . $msg . "'";
    return "'money': true";
  }

  private function jquery_validate_notEmpty($model, $field, $params, $msg) {
    CakeLog::write('debug', 'JqueryValidate->notEmpty: params=' . print_r($params, true));
    $this->validation_messages[] = "required: '" . $msg . "'";
    return "'required': true";
  }

  private function jquery_validate_numeric($model, $field, $params, $msg) {
    CakeLog::write('debug', 'JqueryValidate->numeric: params=' . print_r($params, true));
    $this->validation_messages[] = "number: '" . $msg . "'";
    return "'number': true";
  }

  private function jquery_validate_naturalNumber($model, $field, $params, $msg) {
    CakeLog::write('debug', 'JqueryValidate->naturalNumber: params=' . print_r($params, true));
    $this->validation_messages[] = "digits: '" . $msg . "'";
    return "'digits': true";
  }

  private function jquery_validate_required($model, $field, $params, $msg) {
    CakeLog::write('debug', 'JqueryValidate->required: params=' . print_r($params, true));
    $this->validation_messages[] = "required: '" . $msg . "'";
    return "'required': true";
  }

  private function jquery_validate_phone($model, $field, $params, $msg) {
    CakeLog::write('debug', 'JqueryValidate->phone: params=' . print_r($params, true));
    $this->validation_messages[] = "phoneUS: '" . $msg . "'";
    return "'phoneUS': true";
  }

  private function jquery_validate_postal($model, $field, $params, $msg) {
    CakeLog::write('debug', 'JqueryValidate->postal: params=' . print_r($params, true));
    $this->validation_messages[] = "minlength: '" . $msg . "'";
    $this->validation_messages[] = "maxlength: '" . $msg . "'";
    return "'minlength': 5, 'maxlength': 5";
  }

  private function jquery_validate_range($model, $field, $params, $msg) {
    CakeLog::write('debug', 'JqueryValidate->range: params=' . print_r($params, true));
    $this->validation_messages[] = "min: '" . $msg . "'";
    $this->validation_messages[] = "max: '" . $msg . "'";
    return "'min': " . $params[1] . ", 'max': " . $params[2];
  }

  private function jquery_validate_ssn($model, $field, $params, $msg) {
    CakeLog::write('debug', 'JqueryValidate->ssn: params=' . print_r($params, true));
    $this->validation_messages[] = "minlength: '" . $msg . "'";
    $this->validation_messages[] = "maxlength: '" . $msg . "'";
    return "'minlength': 9, 'maxlength': 9";
  }

  private function jquery_validate_time($model, $field, $params, $msg) {
    CakeLog::write('debug', 'JqueryValidate->time: params=' . print_r($params, true));
    $this->validation_messages[] = "time: '" . $msg . "'";
    return "'time': true";
  }

  private function jquery_validate_url($model, $field, $params, $msg) {
    CakeLog::write('debug', 'JqueryValidate->url: params=' . print_r($params, true));
    $this->validation_messages[] = "url: '" . $msg . "'";
    return "'url': true";
  }

  private function jquery_validate_uuid($model, $field, $params, $msg) {
    CakeLog::write('debug', 'JqueryValidate->uuid: params=' . print_r($params, true));
    return '';
    $this->validation_messages[] = "uuid: '" . $msg . "'";
    return "'uuid': true";
  }
}

published on Oct 11, 2012 12:00 AM

Read more

JSON with your tables

JSON with your tables

Be able to easily save and retrieve PHP arrays to/from a database’s column Have you ever needed to save a PHP array into your database? Well, this behavior is for that. You won’t have to worry about encoding (when saving) and decoding (when retrieving) your data.

Behavior code below.

How to use in your model:

<?php
class Recipe extends AppModel{

    public $actsAs = array(
        'JsonColumn' => array(
            'fields' => array('additional_info') /** add the fields you wanna encode here **/
        )
    );
?>

That’s it! Now when you save/retrieve data the magic will happens:

<?php class RecipesController extends AppController {
    public function save(){
         // add some fake data here. This could come from a submit/form, for instance
         $this->request->data('Recipe.additional_info', array('flavor' => 'strawberries', 'type' => 'cake'));
         $this->Recipe->save($this->request->data);
    }
}

This will save the following json data into the “additional_info” column:

{"flavor":"strawberries","type":"cake"}

And the following:

$this->Recipe->findById(1);

Will result in:

Array
(
    [Recipe] => Array
        (
            [id] => 1
            [additional_info] => Array
                (
                    [flavor] => strawberries
                    [type] => cake
                )

             ...
            [created] => 2012-10-09 16:46:11
            [updated] => 2012-10-09 16:46:11
        )

)

JsonColumnBehavior.php

<?php
/**
 * Be able to easily save and retrieve PHP arrays to/from a database's column
 *
 * @author Lucas Pelegrino <lucas.wxp@gmail.com>
 */
class JsonColumnBehavior extends ModelBehavior {
/**
 * The default options for the behavior
 *
 * @var array
 * @access public
 */
    public $settings = array(
        'fields' => array()
    );

/**
 * Setup the behavior.
 *
 * @param object $model Reference to model
 * @param array $settings Settings
 * @return void
 * @access public
 */
    public function setup(Model $model, $settings) {
        $this->settings = array_merge($this->settings, $settings);
    }

/**
 *
 * @param object $model Reference to model
 * @access public
 */
    public function beforeSave(Model $model) {
        foreach($this->settings['fields'] as $field){
            if(isset($model->data[$model->alias][$field]))
                $model->data[$model->alias][$field] = $this->_encode($model->data[$model->alias][$field]);
        }
            return true;
    }


/**
 *
 * @param object $model Reference to model
 * @access public
 */
    public function afterFind(Model $model, $results) {
        foreach($results as $i => &$res){
            foreach($this->settings['fields'] as $field){
                if(isset($res[$model->alias][$field]))
                    $res[$model->alias][$field] = $this->_decode($res[$model->alias][$field]);
            }
        }
        return $results;
    }

/**
 * Encode json
 *
 * @param $data
 * @return mixed
 */
    protected function _encode($data){
        return json_encode($data);
    }

/**
 * Decode json
 *
 * @param $data
 * @return mixed
 */
    protected function _decode($data){
        $decode = json_decode($data);
        return is_object($decode) ? (array)$decode : $decode;
    }
}
?>

Have fun!

published on Oct 9, 2012 12:00 AM

Read more

CakePHP 2.2.3 released

CakePHP 2.2.3 released

The CakePHP core team is proud to announce the immediate availability of CakePHP 2.2.3

The CakePHP core team is proud to announce the immediate availability of CakePHP 2.2.3[1]. This is a bugfix/maintenance release for the 2.2.x release branch. Since the release of 2.2.2, there have been 65 commits, and over 70 tickets closed. A short list of the changes you can expect are:

  • virtualField quoting around - was improved again.
  • Errors for SchemaShell and missing schema files/classes were improved.
  • The URL /0 is now properly handled.
  • Model options are now properly forwarded in PaginatorHelper::_pagingLinks().
  • Required field detection in FormHelper was improved.
  • Permission denied redirects in AuthComponent are now relative to the application host.
  • Multiple select boxes now work better with SecurityComponent.
  • Radio buttons with falsey values now select correctly.
  • Exceptions raised in AppController::beforeRender() no longer cause infinite loops.
  • CakeEmail’s autogenerated Message-ID headers no longer contain port numbers.
  • Multiple extensions in layouts that contain elements, now works as expected.
  • Issues where scoped loggers would recieve all messages of matching types was corrected.

A huge thanks to all involved in terms of both contributions through commits, tickets, documentation edits, and those whom have otherwise contributed to the framework. Without you there would be no CakePHP. Download a packaged release [2]

Links

published on Oct 9, 2012 12:00 AM

Read more

ConfigAdmin - Administration of Custom Configuration File

ConfigAdmin - Administration of Custom Configuration File

ConfigAdmin Pulgin is management of custom configuration file. > This is created on top of available functionality in cakephp 2.1<br > Ref: http://book.cakephp.org/2.0/en/development/configuration.html #reading-and-writing-configuration-files > To use this plugin you must have cakephp version 2.1+. <br > This gives ability to end-user to modify key-value pairs in configuration file through simple UI design.

Installation & Usage

1. Download plugin from > 2. Copy Paste ~/plugin/ConfigAdmin folder to your app/Plugin folder. > 3. Copy Paste config_admin_codes.php file into app/Config folder. > 4. That’s it now you can test it. http: /your-project- name/config_admin/settings > If you are testing it on localhost then - Ex. localhost your_project/config_admin/settings > 5. Now you can use config_admin_codes.php file by loading it in your controller to set it in view.<br > 6. Load config_admin_codes at the top of controller. Read it in any of action wherever you want to use configuration file. > Ex. <code><span style=”color: #000000”> <br ><?php App::uses(‘AppController’,’Controller’); Configure::load(‘config_admin_codes’);//Lodingconfigfile classContactsControllerextendsAppController{ publicfunctionindex(){ $this->Contact->recursive=0; $this->set(‘contacts’,$this->paginate()); $codes=Configure::read(‘config_admin_codes’);//Readingconfigfile $this->set($codes);//settingconfigvaluestoview } } ?>

Contact

Email: developers@maxbohr.com

Download

https://github.com/maxbohr/ConfigAdmin/

published on Sep 22, 2012 12:00 AM

Read more

Multistep forms

Multistep forms

One of the features I really love about PHP frameworks is form management. Coding forms in plain PHP can easily become a pain if not well planned out. Multistep forms take this complexity even further, especially when you care about user experience. In this tutorial you’ll be amazed by how much little code can manage a whole full featured multistep form when taking advantage of CakePHP powerful classes. We’ll build the form in only 60 lines of controller code. Original article here, with better syntax highlighting One of the features I really love about PHP frameworks is form management. Coding forms in plain PHP can easily become a pain if not well planned out. Multistep forms take this complexity even further, especially when you care about user experience. In this tutorial you’ll be amazed by how much little code can manage a whole full featured multistep form when taking advantage of CakePHP powerful classes. We’ll build the form in only 60 lines of controller code. The form will have the following features:

  • automagical data management
  • flexible steps control
  • back and forth buttons
  • progress indicator
  • data validation and error messages

For this demo we’ll create a sort of social network style user registration page with four steps and very few fields. We won’t deal with CSS styling since this is not the focus of this tutorial. Complete source is available for download.

Create model and table

Run the following query to create our database table, where we are going to store each submission data. Saving to multiple (related) models is not a problem and should require very little adaption.

CREATE TABLE `users` (
 `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
 `created` datetime DEFAULT NULL,
 `modified` datetime DEFAULT NULL,
 `username` varchar(99) DEFAULT NULL,
 `password` varchar(99) DEFAULT NULL,
 `first_name` varchar(99) DEFAULT NULL,
 `last_name` varchar(99) DEFAULT NULL,
 `mobile` varchar(20) DEFAULT NULL,
 `sex` varchar(6) DEFAULT NULL,
 `birthdate` date DEFAULT NULL,
 `city` varchar(99) DEFAULT NULL,
 `zip` varchar(5) DEFAULT NULL,
 `about` longtext,
 `interests` longtext,
 `job` longtext,
 PRIMARY KEY (`id`)
)

Now let’s create a basic User class with some validation rules at Model/User.php:

class User extends AppModel {
    var $validate = array(
            'username' => array(
                    'unique' => array(
                            'rule' => 'isUnique',
                            'message' => 'User already registered'
                    ),
                    'email' => array(
                            'rule' => 'email',
                            'message' => 'Username must be a valid email address'
                    )
            ),
            'password' => array(
                    'rule' => array('minLength', 6),
                    'message' => 'Minimum six characters please'
            ),
            'first_name' => array(
                    'rule' => 'notEmpty',
                    'message' => 'required field'
            ),
            'last_name' => array(
                    'rule' => 'notEmpty',
                    'message' => 'required field'
            ),
            'mobile' => array(
                    'rule' => 'notEmpty',
                    'message' => 'required field'
            ),
            'birthdate' => array(
                    'rule' => 'notEmpty',
                    'message' => 'required field'
            ),
            'city' => array(
                    'rule' => 'notEmpty',
                    'message' => 'required field'
            ),
            'zip' => array(
                    'numeric' => array(
                            'rule' => 'numeric',
                            'message' => 'zip code can contain only numeric values'
                    ),
                    'lenght' => array(
                            'rule' => array('between', 5,5),
                            'message' => 'zip code must be 5 digits long'
                    )
            )
    );
}

The controller

This is the really interesting part. Using this method, we will have a single method managing write to session/database and validation of every step . A specific view file for each step will be loaded by the controller based on a parameter from the URL. The total number of steps is dynamically calculated by counting the number of view files that start with “msf_step_” (we will name msf_step_1.ctp and so on). If you don’t like this level of dynamicity you can just hardcode the value in your controller’s beforeFilter. Of course, we will also implement a series of checks to prevent users playing with the URL , to arbitrarily skip the steps or load non existent views. Another time saving feature of CakePHP is the ability to restore previously submitted data to the same form with just a single command . In our case, data is saved and retrieved, on each step, using Cake’s Session class. Ok, here is the code of Controller/UsersController.php. Everything is explained in the comments!

class UsersController extends AppController {

    /**
     * use beforeRender to send session parameters to the layout view
     */
    public function beforeRender() {
            parent::beforeRender();
            $params = $this->Session->read('form.params');
            $this->set('params', $params);
    }

    /**
     * delete session values when going back to index
     * you may want to keep the session alive instead
     */
    public function msf_index() {
            $this->Session->delete('form');
    }

    /**
     * this method is executed before starting the form and retrieves one important parameter:
     * the form steps number
     * you can hardcode it, but in this example we are getting it by counting the number of files that start with msf_step_
     */
    public function msf_setup() {
            App::uses('Folder', 'Utility');
            $usersViewFolder = new Folder(APP.'View'.DS.'Users');
            $steps = count($usersViewFolder->find('msf_step_.*\.ctp'));
            $this->Session->write('form.params.steps', $steps);
            $this->Session->write('form.params.maxProgress', 0);
            $this->redirect(array('action' => 'msf_step', 1));
    }

    /**
     * this is the core step handling method
     * it gets passed the desired step number, performs some checks to prevent smart users skipping steps
     * checks fields validation, and when succeding, it saves the array in a session, merging with previous results
     * if we are at last step, data is saved
     * when no form data is submitted (not a POST request) it sets this->request->data to the values stored in session
     */
    public function msf_step($stepNumber) {

            /**
             * check if a view file for this step exists, otherwise redirect to index
             */
            if (!file_exists(APP.'View'.DS.'Users'.DS.'msf_step_'.$stepNumber.'.ctp')) {
                    $this->redirect('/users/msf_index');
            }

            /**
             * determines the max allowed step (the last completed + 1)
             * if choosen step is not allowed (URL manually changed) the user gets redirected
             * otherwise we store the current step value in the session
             */
            $maxAllowed = $this->Session->read('form.params.maxProgress') + 1;
            if ($stepNumber > $maxAllowed) {
                    $this->redirect('/users/msf_step/'.$maxAllowed);
            } else {
                    $this->Session->write('form.params.currentStep', $stepNumber);
            }

            /**
             * check if some data has been submitted via POST
             * if not, sets the current data to the session data, to automatically populate previously saved fields
             */
            if ($this->request->is('post')) {

                    /**
                     * set passed data to the model, so we can validate against it without saving
                     */
                    $this->User->set($this->request->data);

                    /**
                     * if data validates we merge previous session data with submitted data, using CakePHP powerful Hash class (previously called Set)
                     */
                    if ($this->User->validates()) {
                            $prevSessionData = $this->Session->read('form.data');
                            $currentSessionData = Hash::merge( (array) $prevSessionData, $this->request->data);

                            /**
                             * if this is not the last step we replace session data with the new merged array
                             * update the max progress value and redirect to the next step
                             */
                            if ($stepNumber < $this->Session->read('form.params.steps')) {
                                    $this->Session->write('form.data', $currentSessionData);
                                    $this->Session->write('form.params.maxProgress', $stepNumber);
                                    $this->redirect(array('action' => 'msf_step', $stepNumber+1));
                            } else {
                                    /**
                                     * otherwise, this is the final step, so we have to save the data to the database
                                     */
                                    $this->User->save($currentSessionData);
                                    $this->Session->setFlash('Account created!');
                                    $this->redirect('/users/msf_index');
                            }
                    }
            } else {
                    $this->request->data = $this->Session->read('form.data');
            }

            /**
             * here we load the proper view file, depending on the stepNumber variable passed via GET
             */
            $this->render('msf_step_'.$stepNumber);
    }
}

The views

This is the easiest part. Here is the content of each step view.

// View/Users/msf_step_1.ctp
echo $this->Form->create('User');
echo $this->Form->input('username');
echo $this->Form->input('password');
echo $this->Form->input('first_name');
echo $this->Form->input('last_name');
echo $this->Form->end('Next step');

// View/Users/msf_step_2.ctp
echo $this->Form->create('User');
echo $this->Form->input('birthdate');
echo $this->Form->input('sex');
echo $this->Form->input('mobile');
echo $this->Html->link('Previous step',
    array('action' => 'msf_step', $params['currentStep'] -1),
    array('class' => 'button')
);
echo $this->Form->end('Next step');

// View/Users/msf_step_3.ctp
echo $this->Form->create('User');
echo $this->Form->input('city');
echo $this->Form->input('zip');
echo $this->Html->link('Previous step',
    array('action' => 'msf_step', $params['currentStep'] -1),
    array('class' => 'button')
);
echo $this->Form->end('Next step');


// View/Users/msf_step_4.ctp
echo $this->Form->create('User');
echo $this->Form->input('about');
echo $this->Form->input('interests');
echo $this->Form->input('job');
echo $this->Html->link('Previous step',
    array('action' => 'msf_step', $params['currentStep'] -1),
    array('class' => 'button')
);
echo $this->Form->end('Save');
?>

// View/Users/msf_index.ctp
echo $this->Html->link('Start form >', array('action' => 'msf_setup'));

A little bit of editing of the layout file is needed to display the progress indicator, which also provides link functionality, allowing to users to jump back and forth. Place this code in your layout file where you want the progress indicator to appear.

for ($i=1; $i <= $params['steps']; $i++) {
    if ($i > $params['maxProgress'] + 1) {
            echo 'Step '.$i.'';
    } else {
            $class = ($i == $params['currentStep']) ? 'active' : 'normal';
            echo $this->Html->link('Step '.$i,
                    array('action' => 'msf_step', $i),
                    array('class' => $class)
            );
    }
}

Some CSS styling is required to properly display the indicator, and you can find my version in the zipped source.

Conclusion

This is just an example of how much CakePHP can help you write less and better code. I hope you liked it! Share your thoughts using the comments below.

published on Sep 9, 2012 12:00 AM

Read more

Google Maps Helper

Google Maps Helper

# Google Maps Helper for CakePHP 2.x Helper for CakePHP framework that integrates a Google Map in your view using Google Maps API V3.

Download

https://github.com/marcferna/CakePHP-GoogleMapHelper

Installation

  1. Place the helper into app/View/Helper/GoogleMapHelper.php
  2. Add this line into the controller : `php public $helpers = array('GoogleMap'); //Adding the helper `
  3. Then we need to add the necessary Javascript files into the view : `php<?= $this->Html->script('`http://maps.google.com/maps/api/js?sen sor=true',`_ false); ?> ` Note that the API key is not required but it you may want to add it if you want to monitor your usage or to buy additional usage quota. To add the api key: `php<?= $this->Html->scr ipt('`http://maps.google.com/maps/api/js?key=YOUR_API_KEY&sensor=true' ,`_ false); ?> `

Usage

Print the map to your view `phpGoogleMap->map(); ?> `

Map Options

Below are the options available to set to your map:

**id:** Map
canvas id * **width:** Map width * **height:** Map height * **style:**
Map canvas CSS style * **zoom:** Map zoom * **type:** Type of map -
`ROADMAP`, `SATELLITE`, `HYBRID` or `TERRAIN` * **custom:** Any other
map option not mentioned before and available for the map. For example
`mapTypeControl: true`. See more map options at:
https://developers.google.com/maps/documentation/javascript/controls *
**localize:** Boolean to localize your position or not. Overrides
'latitude' & 'longitude' and 'address' (Localize have priority versus
Latitude & Longitude and Address) * **latitude:** Default latitude if
the browser doesn't support localization or you don't want
localization (Latitude & Langitude have priority versus Address) *
**longitude:** Default longitude if the browser doesn't support
localization or you don't want localization (Latitude & Langitude have
priority versus Address) * **address:** Default address if the browser
doesn't support localization or you don't want localization (Latitude
& Langitude have priority versus Address) * **marker:** Boolean to put
a marker in your position or not * **markerTitle:** Marker title (HTML
title tag) * **markerIcon:** Default icon of the marker of your
position * **markerShadow:** Default icon' shadow of the marker of
your position * **infoWindow:** Boolean to show an information window
when you click your position marker or not * **windowText:** Default
text inside your position marker´s information window

In order modify any of the default options shown above you need to create your map passing the array as follows:

<?php
// Override any of the following default options to customize your map
$map_options = array(
    'id' => 'map_canvas',
    'width' => '800px',
    'height' => '800px',
    'style' => '',
    'zoom' => 7,
    'type' => 'HYBRID',
    'custom' => null,
    'localize' => true,
    'latitude' => 40.69847032728747,
    'longitude' => -1.9514422416687,
    'address' => '1 Infinite Loop, Cupertino',
    'marker' => true,
    'markerTitle' => 'This is my position',
    'markerIcon' => 'http://google-maps-icons.googlecode.com/files/home.png',
    'markerShadow' => 'http://google-maps-icons.googlecode.com/files/shadow.png',
    'infoWindow' => true,
    'windowText' => 'My Position'
);
?>

<?= $this->GoogleMap->map($map_options); ?>

Adding Markers

To add a marker use:

GoogleMap->addMarker($map_id, $marker_id,
$position); ?> ``` Where: * **$map_id** is the map canvas id
('map_canvas' by default) * **$marker_id** is the unique identifiyer
for that marker * **$position** could be a simple string with the
address or an array with latitude and longitude.
Example with address (using geolocation) ```php<?=
$this->GoogleMap->addMarker("map_canvas", 1, "1 Infinite Loop,
Cupertino, California");

Example with latitude and longitude:

<?= $this->GoogleMap->addMarker("map_canvas", 1, array('latitude' => 40.69847, 'longitude' => -73.9514)); ?>

Marker Options

There are some marker options available to customize the marker popup info window: * showWindow: Boolean to show or not the popup info window * windowText: Text to show inside the popup info window * markerTitle: Marker title (HTML title tag) * markerIcon: Marker icon * markerShadow: Marker icon shadow In order modify any of the default options shown above you need to create your marker passing the array as follows:

<? // Override any of the following default options to customize your
marker $marker_options = array( 'showWindow' => true, 'windowText' =>
'Marker', 'markerTitle' => 'Title', 'markerIcon' =>
'`http://labs.google.com/ridefinder/images/mm_20_purple.png',`_
'markerShadow' =>
'`http://labs.google.com/ridefinder/images/mm_20_purpleshadow.png',`_
); ?>

<?= $this->GoogleMap->addMarker("map_canvas", 1, "1 Infinite Loop,
Cupertino, California", $marker_options); ?>

published on Sep 8, 2012 12:00 AM

Read more

For the Core Translation Behavior (i18n)

For the Core Translation Behavior (i18n)

I started using the Core Translation Behavior. I discovered that if I added a record, it was only being added in ONE language. I don’t know how other people create the records in the i18m table for the other languages, at the same time. What I did is a little hack on the TranslateBehavior’s afterSave, so if the record was $created it would be created in ALL languages I have defined in my core.php.

I have all the languages used in my App defined in core.php as

Configure::write('Config.languages', array(
    'spa' => __('Español', true),
    'eng' => __('English', true),
));

So it is easy to add them to a selectbox and select the language.

I first copied translate.php from CakePHP core files into my APP/models/behavior directory.

Then, the change in the translate.php afterSave method is as follows:

function afterSave(&$model, $created) {
      if (!isset($this->runtime[$model->alias]['beforeSave'])) {
        return true;
    }

    if ($created) {
        if (!($locales = Configure::read('Config.languages'))) {
            $locale = $this->_getLocale($model);
            $locales = array($locale => $locale);
        }
    } else {
        $locale = $this->_getLocale($model);
        $locales = array($locale => $locale);
    }

    foreach($locales as $locale => $localeName) {
        $tempData = $this->runtime[$model->alias]['beforeSave'];
        $conditions = array('model' => $model->alias, 'foreign_key' => $model->id);
        $RuntimeModel =& $this->translateModel($model);

        foreach ($tempData as $field => $value) {
            unset($conditions['content']);
            $conditions['field'] = $field;
            if (is_array($value)) {
                $conditions['locale'] = array_keys($value);
            } else {
                $conditions['locale'] = $locale;
                if (is_array($locale)) {
                    $value = array($locale[0] => $value);
                } else {
                    $value = array($locale => $value);
                }
            }
            $translations = $RuntimeModel->find('list', array('conditions' => $conditions, 'fields' => array($RuntimeModel->alias . '.locale', $RuntimeModel->alias . '.id')));
            foreach ($value as $_locale => $_value) {
                $RuntimeModel->create();
                $conditions['locale'] = $_locale;
                $conditions['content'] = $_value;
                if (array_key_exists($_locale, $translations)) {
                    $RuntimeModel->save(array($RuntimeModel->alias => array_merge($conditions, array('id' => $translations[$_locale]))));
                } else {
                    $RuntimeModel->save(array($RuntimeModel->alias => $conditions));
                }
            }
        }
    }
    unset($this->runtime[$model->alias]['beforeSave']);
}

I haven’t tried it much yet, but I think it work alright. Please, let me know if there’s a better way to do it... or if you have troubles...

published on Sep 1, 2012 12:00 AM

Read more

CakePHP 2.2.2 release

CakePHP 2.2.2 release

The CakePHP core team is proud to announce the immediate availability of CakePHP 2.2.2[1]. This is a bugfix/maintenance release for the 2.2.x release branch. Since the release of 2.2.1, there have been over 80 commits, and 39 tickets closed.

The CakePHP core team is proud to announce the immediate availability of CakePHP 2.2.2[1]. This is a bugfix/maintenance release for the 2.2.x release branch. Since the release of 2.2.1, there have been over 80 commits, and 39 tickets closed.

A short list of the changes you can expect are:

  • Configure::load() and Configure::dump() are now more consistent, and create a new PhpReader by default.
  • Error messaging is better for when fixture creation fails.
  • Logging on windows has been improved, and log levels are more correct.
  • Generated schema files no longer contain multiple primary keys.
  • Namespaced elements work correctly in the RssHelper now.
  • ( and ) are now correctly handled by TextHelper::autoLinkUrls()
  • Applications can now define LOGS and CACHE constants.
  • Recursive errors in debug() have been fixed in 5.2 and 5.3.
  • requestAction() now more correctly simulates GET requests, when the preceding request is a POST or PUT.
  • ModelValidator state is reset when models are created/saved.
  • Additional mimetypes added for Microsoft Office document formats.
  • Validation::decimal() reworked to fix a few edge cases.
  • Virtual fields containing - are quoted more correctly now.

A huge thanks to all involved in terms of both contributions through commits, tickets, documentation edits, and those whom have otherwise contributed to the framework. Without you there would be no CakePHP.

Links

published on Sep 1, 2012 12:00 AM

Read more

User Management Plugin for cakephp 2.x version 2.0

User Management Plugin for cakephp 2.x version 2.0

I have launched a new version(2.0) of my plugin for user management. Demo at http://umpremium.ektasoftwares.com

This plugin is Basic need of your website. Basically It gives you all features which you need on starting your website or a project in cakephp 2.x framework.

It is very helpful for Beginners because of following features-

Clean code with coding standards
Proper documentations
Newbie will learn- a. How to write code in Cakephp? b. How to use CSRF/XSS protection in cakephp c. How to use SSL/HTTPS in cakephp for whole site as well as only some pages. d. How to use Ajax Pagination in cakephp. e. How to use Ajax Form Validations with File/Image in cakephp.

and many more. For all features,Beginners please have a look on http://developers.ektasoftwares.com/docs/umpremium/beginners.html

Experts will also learn many other things. For all features http://umpremium.ektasoftwares.com

You can start your project or a website in few minutes with this plugin because this plugin has all things which you can think in starting of your project.

The main features are-

Login with Facebook, Twitter, Linkedin, Four Square, Gmail, Yahoo.
All Configurations are database driven. No need to touch php code for config setting.
No need to hard code your site URL any where.
View Online users and guest and admin can take many action on online users.
SSL support for selected pages or whole site.
Most of the things are Ajax driven.

I cannot describe all features here so please have a look on demo at http://umpremium.ektasoftwares.com here you can find all features of this plugin.

published on Aug 20, 2012 12:00 AM

Read more

Like plugin

Like plugin

Add a Facebook-like ‘Like’ feature to your CakePHP 2.x powered web application.

Installation

  1. Download the plugin and place it in app/Plugin

https://github.com/aschelch/cakephp-like-plugin/zipball/master

or via Git

git submodule add git://github.com/aschelch/cakephp-like-plugin.git app/Plugin/Like

2. Load the plugin by adding at the bottom of your file Config/bootstrap.php

CakePlugin::load('Like', array('routes' => true));
  1. Create the table using the shell command :
Console/cake Like.install
  1. Attach the Likeable behavior to the Model
public Post extends AppModel{
    $actsAs = array('Like.Likeable');
}

That’s all !

Usage

In the controller

Then to use it in your controller, you can do :

Like an item

$this->Post->like($post_id, $this->Auth->user('id'));

Dislike an item

$this->Post->dislike($post_id, $this->Auth->user('id'));

Find all items liked by an user

$this->Post->findLikedBy($this->Auth->user('id'));

Test if an user like an item

if($this->Post->isLikedBy($post_id, $this->Auth->user('id'))){...}

Find the most liked item

$this->Post->find('most_liked', array('limit'=>5));

In the view

Add the helper in your controller :

public PostController extends AppController{
    public $helpers = array('Like.Like');
}

And, in your view:

$this->Like->like('post', $post_id);
$this->Like->dislike('post', $post_id);

published on Aug 10, 2012 12:00 AM

Read more

FileStorage plugin with optional Image Processing

FileStorage plugin with optional Image Processing

This plugin is giving you the possibility to store files in virtually any kind of storage backend. This plugin is wrapping the Gaufrette library (https://github.com/KnpLabs/Gaufrette) library in a CakePHP fashion and provides a simple way to use the storage adapters through the StorageManager class. Storage adapters are an unified interface that allow you to store file data to your local file system, in memory, in a database or into a zip file and remote systems. There is a database table keeping track of what you stored were.

Adapters

Included storage adapters through the Gaufrette vendor lib are

Local File System
Amazon S3
ACL Aware Amazon S3
Mogile FS
Rackspace Cloudfiles
Zip File
Ftp
Sftp
In Memory
Grid FS
Apc
Doctrine DBAL

You can always write your own adaper or extend and overload existing ones.

StorageManager::config('Local', array(
    'adapterOptions' => array(TMP, true),
    'adapterClass' => '\Gaufrette\Adapter\Local',
    'class' => '\Gaufrette\Filesystem'));

0 To configure adapters use the StorageManager::config method. First argument is the name of the config, second an array of options for that adapter B0x1A1 To invoke a new instance using a before set configuration call:

$Adapter = StorageManager::adapter('Local');

You can also call the adapter instances methods like this

StorageManager::adapter('Local')->write($key, $data);

Alternativly you can pass a config array as first argument to get an instance using these settings that is not in the configuration.

To delete configs and by this the instance from the StorageManager call

StorageManager::flush('Local');

If you want to flush all adapter configs and instances simply call it without the first argument.

How to store an uploaded file

The basic idea of this plugin is that files are always handled as separate entities and are associated to other models.

So for example let’s say you have a Report model and want to save a pdf to it, you would then create an association lile:

public $hasOne = array(
    'PdfFile' => array(
        'className' => 'FileStorage.FileStorage',
        'foreignKey' => 'foreign_key'));

In your add/edit report you would have something like:

echo $this->Form->input('Report.title');
echo $this->Form->input('PdfFile.file');
echo $this->Form->input('Report.description');

Now comes the crucial point of the whole implementation:

Because of to many different requirements and personal preferences out there the plugin is not automatically storing the file. You’ll have to customize it a little but its just a matter for a few lines.

Lets go by this scenario inside the report model, assuming there is an add() method:

$this->create()
if ($this->save($data)) {
    $key = 'your-file-name';
    if (StorageManager::adapter('Local')->write($key, file_get_contents($this->data['PdfFile']['tmp_name']))) {
        $this->data['PdfFile']['foreignKey'] = $this->getLastInsertId();
        $this->data['PdfFile']['model'] = 'Report';
        $this->data['PdfFile']['path'] = $key;
        $this->data['PdfFile']['adapter'] = 'Local';
    }
}

Later, when you want to delete the file, for example in the beforeDelete() or afterDelete() callback of your Report model, you’ll know the adapter you have used to store the attached PdfFile and can get an instance of this adapter configuration using the StorageManager. By having the path or key available you can then simply call:

StorageManager::adapter($data['PdfFile']['adapter'])->delete($data['PdfFile']['path']);

Insted of doing all of this in the model that has the files associated to it you can also simply extend the FileStorage model from the plugin and add your storage logic there and use that model for your association.

Why is it done like this?

Because every developer might want to store the file at a different point or apply other operations on the file before or after it is store. Based on different circumstances you might want to save an associated file even before you created the record its going to get attached to, in other scenarios like in this documentation you want to do it after.

The $key is also a key aspect of it: Different adapters might expect a different key. A key for the Local adapter is usally a path and a file name under which the data gets stored. Another adapter might require a UUID. That is also the reason why you use file_get_contents() instead of simply passing the tmp path as it is.

Download

You can get the plugin from http://github.com/burzum/FileStorage

I consider it as stable, I’ve used it for some time now without issue, we have it used in an internal CakeDC project without issues and I have not received a bug report yet from the 13 followers at this time.

If you find bugs or have suggestions please use the git issue tracker to report them.

published on Aug 9, 2012 12:00 AM

Read more

Alternate way to save HABTM data along with primary model

Alternate way to save HABTM data along with primary model

The CakePHP documentation on saving HABTM data didn’t cover a use-case my app needed. My form submits a comma-separated list of associated- model ids to save with a user. With a little data-format massaging, I found a way to save it all with one call to Model->save(...).

My app has a schema with a User model and Equipment model that share a HABTM relationship. In other words, one or more users may be the go-to contacts for one or more pieces of equipment. Because there are already over 100 pieces of equipment, using a multi-select drop-down or checkboxes for Equipment on the User edit form might get awkward and unwieldy on what should be a simple form. So I took a different tack and used an auto-complete edit box. When the user types part of a name and selects a piece of equipment from the displayed matches, it shows that piece of equipment in the list of equipment already associated with that user along with a little “x” icon that will allow him to remove it again. Using the auto-complete box and the “x” image- links, he can add or remove equipment from the list until he is ready to submit the form.

When the user submits the form, a Javascript submit-event-handler generates an array of ids of the form “1,2,3,4...” and inserts it into a hidden field that gets submitted with the form.

So Controller->request->data will look something like this:

$data = array(
  'Equipment' => '37,97,98',
  'User' => array(
    'id' => '99',
    'username' => 'testuser1',
    'fullname' => 'Test User',
    'phone' => '222-2222',
    'email' => 'foo@bar.baz',
    'Role' => '2'
  ),
);

I need to convert that ‘Equipment’ element to this:

'Equipment' => array(37, 97, 98)

That’s easy:

$data['Equipment'] = array_split(',', $data['Equipment']);

Now I can save the User along with the list of equipment he’s related to:

$result = $this->User->save($data, array(
  'validate' => true,
  'fieldList' => null,
));

I’m taking the time to post this because I struggled with this for some time. The documentation seemed to indicate that I needed to post an array like this:

$data = array(
  'Equipment' => array(
      array('equipment_id' => 37),
      array('equipment_id' => 97),
      array('equipment_id' => 98),
  ),
  'User' => array(
    'id' => '1',
    'username' => 'testuser1',
    'fullname' => 'Test User',
    'phone' => '222-2222',
    'email' => 'foo@bar.baz',
    'Role' => '2'
  ),
);

That resulted in the Cake core generating one insert statement for equipment_id=37, followed by two update statements for id’s 97 and 98. So the final result would be that the query

select * from equipment_users where user_id = 99

would produce only

array(
(int) 0 => array(
    'equipment_users' => array(
        'equipment_id' => '98',
        'user_id' => '1'
    )
)
)

instead of the desired

array(
(int) 0 => array(
    'equipment_users' => array(
        'equipment_id' => '98',
        'user_id' => '1'
    )
),
(int) 1 => array(
    'equipment_users' => array(
        'equipment_id' => '37',
        'user_id' => '1'
    )
),
(int) 2 => array(
    'equipment_users' => array(
        'equipment_id' => '97',
        'user_id' => '1'
    )
)
)

I hope this helps someone. I also hope that one of the regular contributors to the CakePHP documentation can work with me to find a way to include this use-case in the chapter on Saving Your Data.

published on Aug 4, 2012 12:00 AM

Read more

Integrating cakephp with OpenId

Integrating cakephp with OpenId

this article tells how to integrate openid with your cake..........

Click To View Complete Tutorial

Today everyone is in a rapid hustle. So mostly internet users find registration process as very time consuming. Sometimes they might leave your web product if they just want to avoid that annoying registration process. So a very good alternative to this is using `OpenId`_. OpenId is a great way to make your authentication system even more flexible. To implement this feature we must have a basic working authentication system. Click to know how to build basic authentication system.

Prerequisites

First of all your PHP must have OpenID Library. You can download it from this here. When you are done with downloading library then extract the folder named as Auth into your web application’s /app/vendors/ folder. Note: folder is /app/vendors/ not /vendors/ which is in root of your web app besides your app folder. Second you must have OpenId plugin for Cakephp. To download this plugin follow this link. Now similarly extract this download to your /app/plugins/ folder. After extracting you will have openid folder inside your /app/plugins/.

Coding

  • First of all you need to replace that OpenId’s Auth component with cakephp’s default Auth component. To do that edit your ` appcontroller.php` file. By implementing below code will extend Auth component functionality. One thing that is very important here is that you still have power of old Auth Component. You can still use it’s variables and functions i.e ` $this->Auth->allow(“*”);`
var $components = array(
      'Openid.OpenAuth'
);
  • Now you need to edit your ` login.ctp` view file. When below form is submitted then Auth component will try to login user with username and password field. But if it failed to login with username and password then it will check whether OpenId URL is specified or not. If this happens then it will attempt to authenticate URL against OpenID server. If permission granted then OpenAuth component will add user to the session. <?php echo$this->Form->create(array(‘action’=>’login’)); echo$this->Form->input(array(‘openid’=>array(‘label’=>’OpenIDURL’))); echo$this->Form->input(‘username’); echo$this->Form->input(‘password’); echo$this->Form->end(‘Login’); ?>

Final words

This is it, after this all we have working authentication system with OpenId.

Click To View Complete Tutorial

published on Jul 31, 2012 12:00 AM

Read more

CakeFest 2012 - Only 30 days until CakeFest!

CakeFest 2012 - Only 30 days until CakeFest!

With only 30 days remaining until CakeFest 2012, now is the best time to secure your tickets and book your travel!

Organising CakeFest 2012 has been a thrilling experience. We’ve got plenty of interesting talks lined up, sponsors attending the event, and some kickass keynotes to be delivered.

On top of that, the team have been (secretly) designing a special CakePHP CakeFest 2012 T-Shirt that attendees will be able to get a peek at during the conference.

I’m always excited by the leadup to CakeFest, and this year is no different. We have talks from all over the world, and we have a great schedule lined up.

If you have not purchased your ticket for CakeFest yet, we strongly suggest doing this as soon as possible, in addition to booking any required accommodation to ensure that you don’t miss out. For those that are interested in cheaper accommodation close to the conference; the Manchester Conference Centre where the event is being hosted, offers student accommodation rooms. You don’t need to be a student to book them, they are just basic accommodation, at a cheap rate. This is tehe best way to experience CakeFest at a reduced cost. Besides, most of your time will be spent at the conference, or at the bar!

NOTE: The student rooms are listed as “Weston Hall” when making a booking.

Again, I am excited to be attending and organising this event, and I am keen to catch up with the regulars, as well as meet lots of new faces in the CakePHP community.

See you in Manchester for CakeFest 2012!

Link: CakeFest website

Link: Manchester Conference Centre

published on Jul 31, 2012 12:00 AM

Read more

Auth Component of Cakephp Demystified Part-2

Auth Component of Cakephp Demystified Part-2

Auth Component Variables Properly explained....

Click To View Complete Tutorial Jump to Auth Component of Cakephp Demystified Part-1

In our previous post, we learned how to implement a very basic but effective authentication system to make secure areas in our web application. Here the thing is that you could make complex and better authentication system, which we will be doing in our next post of this series. To do that we need to learn basic parts of our Auth component. In this post we will only cover variables and in next post we will discuss important functions.

Variables which are mostly used.

  • string $authError = null It is of string type and mainly used to provide error messages when a user attempts to access an area to which he doesn’t have the permission to access. You can set this in beforeFilter() or as arguments to Auth component. Example :
function beforeFilter()
{
        $this->Auth->authError="You don't have access to that area. Please login first.";
}
  • boolean $autoRedirect = true It determines whether AuthComponent will automatically redirect and exit if login is successful. The importance of this variable is that if you have custom code (cookies, last login) in your login() action which you want to execute then you need to set it to false, so Auth doesn’t auto redirect. If it is set to true then whatever code you have in your login() is not executed. Example :
function beforeFilter()
{
      $this->Auth->autoRedirect=false;
}

function login()
{
if($this->Auth->user()!=null)
       {
             $this->User->id=$this->Auth->user('id');
             $current = date("F j, Y, g:i a");
             $this->User->saveField('last_login',$current);
             $this->redirect(array('controller'=>'users','action'=>'profile'));
        }
}
  • array $data = array() This variable holds form data of controller. Example :
function login()
{
if($this->Auth->data['User']['username']!=null)
         {
               //your code;
           }
}
  • array $fields = array(‘username’ => ‘username’, ‘password’ => ‘password’) It allows us to tell Auth that against which fields of our Model it needs to validate users. By default it is username and password. But suppose if someone have fields in database table as email and secret_word and he wants to use these fields for authentication, then we need this variable. Example :
function beforeFilter()
{
 $this->Auth->fields=array('username'=>'email','password'=>'secret_word');
}
  • mixed $loginAction = null This variable holds login action URL, by default it is login(). But if we have some other function which is handling our login process then we need to provide path in this variable. We can set url with the help of string or using array(); Example :
function beforeFilter()
{
//using string
 $this->Auth->loginAction="/users/authenticate";
//or using array notation
 $this->Auth->loginAction=array('controller'=>'users','action'=>'authenticate');
}
  • string $loginError = null Error to display when user login fails. For security purposes, only one error is used for all login failures, so as not to expose information on why the login failed. But we can also customize it in our login system. In views to output it we need to use session helper; i.e <?phpecho$this->Session->flash(‘Auth’);?> Example :
function beforeFilter()
{
  $this->Auth->loginError="Username or password entered is incorrect. Please try again.";
}
  • mixed $loginRedirect = null Normally, if a user is redirected to the $loginAction page, the location they were redirected from will be stored in the session so that they can be redirected back after a successful login. If this session value is not set, the user will be redirected to the page specified in $loginRedirect. Example :
function beforeFilter()
{
  $this->Auth->loginRedirect=array('controller'=>'users','action'=>'profile');;
}
  • mixed $logoutRedirect = null This holds URL of default action to be invoked as soon as user is logged out of the web application. This URL will be returned from logout() of AuthComponent. Example :
function beforeFilter()
{
  $this->Auth->logoutRedirect=array('controller'=>'pages','action'=>'home');
}
  • string $userModel = ‘User’ Suppose you have saved your users in a database table named as Clients or People, then we need to specify this to Auth component so that it can validate accordingly, if we don’t give this info it will look for users table, so that is wrong. Example :
function beforeFilter()
{
  $this->Auth->userModel="clients";
}
  • array $userScope = array() This is one of the most important variable i found to use. So where this can be used... basically AuthComponent only uses username and password to validate against. But suppose if you have three fields i.e usertype, username, password then this variable is very handy to use. So let us see how it is used. Below code will only validate admin type users. Another use of this could be like checking a user is activated or not in same way as below. Just replace ` ‘User.usertype’=>”admin”` with ` ‘User.activated’=>”1”` Example :
function beforeFilter()
{
     $this->Auth->userScope = array(
                                            'User.usertype' => "admin"
                                      );
}

Final words...

In this post we surfed through different variables (although this is not the complete list of variables) which can be used to customize behavior of AuthComponent. The next post is about functions of AuthComponent.
Jump to Auth Component of Cakephp Demystified Part-3

published on Jul 28, 2012 12:00 AM

Read more

Social login with Hybridauth

Social login with Hybridauth

HybridAuth enable developers to easily build social applications to engage websites vistors and customers on a social level by implementing social signin, social sharing, users profiles, friends list, activities stream, status updates and more. HybridAuth goal is to act as an abstract api between your application and various social apis and identities providers such as Facebook, Twitter, MySpace and Google. This article hopefully can improve Hybridauth support for CakePHP

First of all : Sorry about my English, and this is my first post so correct this article if I’m doing wrong. :)

> <h1>Social login with Hybridauth< h1> Hybridauth extend our application to use social provider authentication in our application. It can combine with Auth component without any problem. The concept is simple (as far as i know), Hybridauth will authenticate using our social provider identity (like Facebook, Twitter, Google, etc..) then return an object to our application which we can use it as we want. ><br >

How to use

1. Download Hybridauth (stable version work with this article is version 2.0.11) > 2. Place hybridauth folder into our application webroot folder (app webroot/hybridauth) > 3. In Your UsersController add:<br >

session_start();

in top most of your controller. > Note: maybe You need to place session_start() in top most of your AppController if you’re using auth component<br > > then create functions: <pre> public function loginwith($provider) { / $this->autoRender = false; require_once( WWW_ROOT . ‘hybridauth/Hybrid/Auth.php’ ); $hybridauth_config = array( “base_url” => ‘http://‘ . $_SERVER[‘HTTP_HOST’] . $this->base . “/hybridauth/”, // set hybridauth path “providers” => array( “Facebook” => array( “enabled” => true, “keys” => array(“id” => “your_fb_api_key”, “secret” => “fb_api_secret”), “scope” => ‘email’, ), “Twitter” => array( “enabled” => true, “keys” => array(“key” => “twitter_api_key”, “secret” => “twitter_api_secret”) ) // for another provider refer to hybridauth documentation ) ); try { // create an instance for Hybridauth with the configuration file path as parameter $hybridauth = new Hybrid_Auth($hybridauth_config); // try to authenticate the selected $provider $adapter = $hybridauth->authenticate($provider); // grab the user profile $user_profile = $adapter->getUserProfile(); //debug($user_profile); //uncomment this to print the object //exit(); //$this->set( ‘user_profile’, $user_profile ); //login user using auth component if (!empty($user_profile)) { $user = $this->_findOrCreateUser($user_profile, $provider); // optional function if you combine with Auth component unset($user[‘password’]); $this->request->data[‘User’] = $user; if ($this->Auth->login($this->request->data[‘User’])) { $this->redirect($this->Auth->redirect()); $this->Session->setFlash(‘You are successfully logged in’); } else { $this->Session->setFlash(‘Failed to login’); } } } catch (Exception $e) { // Display the recived error switch ($e->getCode()) { case 0 : $error = “Unspecified error.”; break; case 1 : $error = “Hybriauth configuration error.”; break; case 2 : $error = “Provider not properly configured.”; break; case 3 : $error = “Unknown or disabled provider.”; break; case 4 : $error = “Missing provider application credentials.”; break; case 5 : $error = “Authentification failed. The user has canceled the authentication or the provider refused the connection.”; break; case 6 : $error = “User profile request failed. Most likely the user is not connected to the provider and he should to authenticate again.”; $adapter->logout(); break; case 7 : $error = “User not connected to the provider.”; $adapter->logout(); break; } // well, basically you should not display this to the end user, just give him a hint and move on.. $error .= “Original error message: ” . $e->getMessage(); $error .= “Trace: ” . $e->getTraceAsString(); $this->set(‘error’, $error); } } // this is optional function to create user if not already in database. you can do anything with your hybridauth object private function _findOrCreateUser($user_profile = array(), $provider=null) { if (!empty($user_profile)) { $user = $this->User->find(‘first’, array(‘conditions’ => array( ‘OR’=>array(‘User.username’ => $user_profile->identifier, ‘User.email’=>$user_profile->email)))); if (!$user) { $this->User->create(); $this->User->set(array( ‘group_id’ => 2, ‘first_name’ => $user_profile->firstName, ‘last_name’ => $user_profile->lastName, ‘email’ => $user_profile->email, ‘username’ => $user_profile->identifier, ‘password’ => AuthComponent::password($user_profile->identifier), //in case you need to save password to database ‘country’ => $user_profile->country, ‘city’ => $user_profile->city, ‘address’ => $user_profile->address, //add another fields you want )); if ($this->User->save()) { $this->User->recursive = -1; $user = $this->User->read(null, $this->User->getLastInsertId()); return $user[‘User’]; } } else { return $user[‘User’]; } } } 4. In your view (ex. login.ctp) add: > <code><span style=”color: #000000”> <br ><divclass=”login-button- div”> <ahref=”loginwith/facebook”class=”zocialfacebook”>LoginwithFacebook</a > <ahref=”loginwith/twitter”class=”zocialtwitter”>LoginwithTwitter</a> </div> that’s all. > Beside this article you can find <a href=”http: /hybridauth.sourceforge.net/download.html#index”> sample cakephp2 application using Hybridauth here. This article is based on the sample application with very little modification and the credit of this article is for them who create hybridauth and cakephp sample app using hybridauth ><br > Happy baking..

published on Jul 27, 2012 12:00 AM

Read more

Auth Component of Cakephp Demystified Part-1

Auth Component of Cakephp Demystified Part-1

how to setup basic authentication system. Complete Toutorial In today’s Internet era most of the web developers tries to provide a log in/signup based feature for web clients in their web applications. Mostly this type of feature is needed only when you want to categories your users a very common example is Guest users and Registered Users. Guest users can access less content on web app while registered users enjoys more privileges. In cakephp this attribute is implemented mostly with the Auth component of this framework. Auth component is a very powerful, robust and can be customized as par the needs of web application. Auth component allows you to quickly set up secure areas in your app. In this series we will be building a complex authentication system. As this is part 1 and starting of this series, in this part we will implement a very basic but fully working authentication scheme.

Getting ready

First of all we need to create a users table in our database to store username and password (hashed version of user’s password). This hashing is done automatically by Auth component using it’s method hashPasswords() when it finds password in $data.

Run below sql to create users table.

CREATE TABLE `users` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`username` VARCHAR(255) NOT NULL,
`password` CHAR(40) NOT NULL,
PRIMARY KEY(`id`)
);

List of all files we will be creating in this post.

  • AppController.php in /app/ folder
  • UsersController.php in /app/controllers/ folder
  • login.ctp in /app/views/users/ folder
  • signup.ctp in /app/views/users/ folder

> <h3>AppController.php File< h3> This file mainly contains global data which is used by all controllers of the application, in our case we have only users controller. This file will be containing below code.

<?php
class AppController extends Controller {
       var $components = array('Session','Auth');
       var $helpers=array('Session');

}
?>

Explanation :

It has two variables one is $components and other one is $helpers. $components variable holds all the components utilized by all controllers, so we specified Auth component. Session component and Session helper is basically used to set session messages and show those messages in view respectively.

UsersController.php File

This is the heart of our logic. It contains functionality of login, signup and logout. Content of this file is...

<?php
class UsersController extends AppController {

    function beforeFilter() {
            parent::beforeFilter();
            $this->Auth->allow('signup');
      }
    function login() {}

    function logout()
    {
        $this->Session->setFlash('You are logged out!');
        $this->redirect($this->Auth->logout());
    }

    function signup()
    {

        if (!empty($this->data)) {
              $this->User->create();
              if ($this->User->save($this->data)) {
              $this->Session->setFlash('User saved!');
              $this->redirect(array('action'=>'login'));
            }
       else {
               $this->Session->setFlash('User not saved! There were some errors. Please rectify them and retry.');
             }

            }

          }

}
?>

Explanation :

First of all, as it is inheriting from AppController, it will have Auth component loaded by default which will process all requests of client. Auth component only allows to access only login function, so to access signup() for adding new users we need beforeFilter() to give that instruction to Auth component to allow signup(). The main thing here to learn is that before Auth component start it’s working, beforeFilter() is invoked . In this we are invoking two beforeFilters one of users controller and other on of app controller by using ` parent::beforeFilter();`

Second function is login(), which is basically called if you put ` http://www.your_domain_name.com/users/login/` in your URL of browser or if you try to access a restricted area of application. When you submit your data by ` login.ctp` file which is view file for this login function then Auth component starts working. First of all it hashes the password field of $data and passes this $data variable to Users Model. Then Model checks and results back to controller. If a valid user is found then Auth adds it in session and grants access to all functions to which it is authorized which is checked by isAuthorized(). But if it finds invalid user, it redirects back to ` login()`.

Third function is logout(), in this function we sets a session’s flash message to let user know that he/she has been logged out. On second line of this function we calling redirect method of controller, which is taking argument from ` $this->Auth->logout()` which is a string containing url to login method.

Our last method is signup(), this is created to add new users. In this we are using create() and save() methods of User Model. Create method initializes the model for writing a new record, loading the default values for those fields that are not defined in $data, and clearing previous validation errors. Especially helpful for saving data in loops. Save method saves model data (based on white-list, if supplied) to the database. By default, validation occurs before save.

login.ctp File

It holds presentation code.Code is...

<?php

echo $this->Form->create(array('action'=>'login));
echo $this->Form->input('username');
echo $this->Form->input('password');
echo $this->Form->end('Login');
?>

Explanation :

This view file utilizes Form Helper to create form elements.

signup.ctp File

It also holds presentation code.In this we have a form so user could submit it with data to create new user...

<?php

echo $this->Form->create(array('action'=>'signup));
echo $this->Form->input('username');
echo $this->Form->input('password');
echo $this->Form->end('Signup');
?>
Jump to Auth Component of Cakephp Demystified Part-2

Complete Toutorial

published on Jul 27, 2012 12:00 AM

Read more

CakeFest 2012 - Schedule posted! Get your tickets now!

CakeFest 2012 - Schedule posted! Get your tickets now!

The CakeFest 2012 talks schedule has been posted on the CakeFest website. Get in and purchase your tickets today before the end of the Early-bird period!

CakeFest 2012 is getting closer every day. With only 45 days to go, now is the best time to jump in and grab your Conference and/or Workshop tickets before the end of the early-bird period.

The schedule has been posted online on the CakeFest Website. Check it out for the latest information about the schedule and talks being given!

The line up this year is spectacular! We have talent from around the world, and some big names from the CakePHP community giving talks on a huge range of topics. CakeFest is simply the best way to learn about CakePHP, to meet new people in the community and to extend your existing skill set.

We’d like to extend a special thankyou to SANIsoft and Microsoft, both of whom are sponsoring CakeFest, and have a long history of supporting CakePHP and the PHP community.

Also, a huge thanks to EngineYard, who have also sponsored the event this year. Its great to see some industry players such as EngineYard showing support for events like CakeFest, and other PHP events around the world.

Again, please checkout the latest information on tickets, and be sure to grab yours before the 21st July, when the Early-Bird period ends!

published on Jul 15, 2012 12:00 AM

Read more

Security Release - CakePHP 2.1.5 & 2.2.1

Security Release - CakePHP 2.1.5 & 2.2.1

CakePHP 2.1.5 and 2.2.1 have just been released. If you are using CakePHP’s Xml class, you should upgrade as soon as possible.

The security issue was recently reported by Paweł Wyleciał. When accepting user provided XML it is possible to read arbitrary files using external entities. This is particularily dangerous for applications accepting XML data as part of a webservice. A possible exploit example would be:

curl -X POST -H ‘Content-Type: application/xml’ locahost/posts -d ‘<!DOCTYPE cakephp [<!ENTITY payload SYSTEM “file:///etc/passwd” >]><Post><body>&payload;</body></Post>]’

Once the XML has been processed $this->request->data[‘Post’][‘body’] will contain the contents of /etc/passwd. This issue was fixed and packaged releases for 2.1 and 2.2 have been created. This issue does not affect the 1.3 or 1.2 release series. If you are unable to upgrade, you should apply the patch as soon as possible. This issue has been assigned CVE-2012-4399 and OSVDB-84042.

Other fixes in 2.2.1

In addition to the security fix 2.2.1 contains fixes for the following issues:

  • Fixed missing urlencode on nested named parameters.
  • Fixed ANSI codes being output on windows terminals.
  • Fixed HtmlHelper::image() including the base directory twice when the fullBase option is used.
  • Console logging now respects the quiet flag for shells.
  • TranslateBehavior now saves records with only some translated fields correctly.
  • afterValidate() was made available on behaviors. This was an omission in 2.2.0.

View the complete changelog for 2.2.1 and 2.1.5. Download a packaged release.

CakeFest 2012 is around the corner and we already expect awesome talks and workshops during the best PHP conference out there. If you haven’t booked your tickets yet, it’s about time you do.

As always, thanks to the friendly CakePHP community for the patches, documentation changes and new tickets. Without you there would be no CakePHP!

Links

[1] http://cakephp.org/changelogs/2.2.1

[2] http://cakephp.org/changelogs/2.1.5

[3] http://github.com/cakephp/cakephp/tags

[4] http://cakefest.org

published on Jul 14, 2012 12:00 AM

Read more

3.0: a peek into CakePHP's future

3.0: a peek into CakePHP’s future

With version 2.2.0 out the team is now focusing on bringing the CakePHP community a major new version with awesome features

Since its creation, more than 7 years ago, CakePHP has grown with a life of its own. Its main goal has always been to empower developers with tools that are both easy to learn and use, leverage great libraries requiring low documentation and low dependencies too. We’ve had several big releases along these years and an ever growing community. Being one of the most popular frameworks out there and probably the first one (!) we have also gotten a lot of criticism from the developer community in general. We have, though, accepted it and learnt from our mistakes to keep building the best PHP framework there is.

CakePHP is known for having a very slow pace of adopting new stuff and it has served very well to its community. Back when we were doing version 2.0 we decided to hold on version 5.2 of PHP for multiple reasons and despite it didn’t let us innovate as much as we wished to, it was an excellent choice given the general environment regarding hosting solutions and general adoption of PHP 5.3. A look back into the past reminded us that we were big innovators in PHP, bringing features to developers that few dreamt possible to do in this language. Now, it’s time to look ahead in future and decide on staying in our comfort zone or take back our leading position as innovators.

So it is with great excitement that we announce we are putting our our efforts in bringing you the next major release of CakePHP. Version 3.0 will leverage the new features in PHP 5.4 and will include an important change in our models and database system. CakePHP 3.0 will not be ready less than 6 or 8 months and we reckon that, given the rise of cheap cloud hosting solutions and upcoming release of new operating system versions, there is no better time to jump on the most current stable version of PHP.

As you may already know, PHP 5.4 offers awesome features that would introduce useful new concepts and interesting solutions to old problems. Closure binding, traits, multibyte support are tools we see of great usefulness for properly implemented advanced framework features we’ve had in mind for a long time. Also new syntax sugar added to the language will make it more pleasant to write both small and complex applications with the framework and a always welcomed free performance increase.

We have a young but already well defined road map for what we want to accomplish in next release and you are invited to contribute and suggest what’s next:

  • Drop support for 5.2.x and support 5.4+ only

  • Add proper namespaces for all classes. This will make it easier to reuse classes outside CakePHP and to use external libraries and finally no chances of collisions between your app classes and core ones.

  • Use traits were possible and makes sense

  • Improve bootstrapping process to allow more developer control and better performance

  • Model layer rewrite:

    • Models to return objects from queries
    • Datamapper-like paradigm
    • Richer query API
    • Support for any database type
    • Support for more database drivers both PDO and native
  • Improve Router:

    • Make it faster
    • Remove named parameters
    • Add support for named routes
    • Smarter router prefixes
    • Shorter url syntax

As you may imagine most of the time will be spent or rewriting the model layer, but it will also be one of the most powerful features CakePHP 3.0 will have. It’s new architecture based on PHP 5.4 capabilities will offer an easier and more powerful set of tools to build web applications in no time.

If you are already as excited as we are this all this new stuff coming, you definitely should meet us on next CakeFest we’ll be talking about the future of CakePHP and hacking our way through to bring you a dev release as soon as possible. Wouldn’t it be lovely to attend to awesome talks, workshops and also be part of the group deciding initial architecture for next major version of the framework? Make sure you book your tickets before we run out of them!

We’re always looking for different people having a vision on software development, are you interested in helping out? There is no better time to start sending patches and become one of the core team!

published on Jul 6, 2012 12:00 AM

Read more

CakePHP 2.2 and 2.1.4 released

CakePHP 2.2 and 2.1.4 released

The CakePHP core team is proud to announce the immediate availability of both CakePHP 2.2.0 stable and 2.1.4 which is the final bugfix release for the 2.1.x branch

The CakePHP team is proud to announce the immediate availability of CakePHP 2.2.0 stable. As mentioned in previous releases, 2.2 is a API compatible release with 2.1 and should be generally transparent when upgrading, except for a few additions you need to make in configuration files. In addition to this release we have also tagged version 2.1.4 which would be the last work we do on the 2.1.x series. Any further stability fixes will be done in 2.2 branch, so we encourage people to upgrade your apps as soon as possible.

CakePHP 2.2 comes with a great set of new features and goodies, here is a quick summary of what you can find after upgrading:

  • Dispatcher filters, a lightweight way of attaching callbacks as middleware to the dispatcher lifecycle for easier caching or faster action responses.
  • New rich api for creating and removing validation rules on the fly for models
  • Seamless pagination for custom find types
  • Support for real nested database transactions
  • Cache groups, a nice way for tagging and mass deleting cache entries using such tags
  • Improved logging support, several new utility methods were added to CakeLog
  • Configure class can now dump stored values into any persistent storage
  • AuthComponent now accepts ` contain` as a key for storing extra user information in session
  • Several improvements to CakeEmail, such as custom header charset, custom themes, setting links domain and custom helpers defined at configuration time
  • PUT and DELETE requests encoded with application/x-www-form- urlencoded will have its data placed into CakeRequest::$data
  • Set class was deprecated in favor of Hash, a faster and more reliable implementation
  • CakeTime is now timezone aware and fully capable of translating dates from one zone to the other
  • CakeTime can now also accept DateTime objects in addition to strings and timestamps
  • FormHelper now shows more reliably required fields based on validation rules
  • HtmlHelper::tableHeaders() now supports setting attributes per table cell.
  • Better web tester experience
  • Improved error handling, featuring custom fatal error templates
  • Redis support for caching
  • Added new validation methods for upload checking and natural numbers

Please make sure you read the complete migration guide available at http://book.cakephp.org/2.0/en/appendices/2-2-migration-guide.html

If you were following each release for 2.2 and 2.1, here’s a summary of the changes that made into this final iteration:

2.1

  • Fixtures will not be loaded again if associated tables exist already in database, making it possible to load fixtures as SQL
  • Better error message in MissingConnectionException when driver is not enabled
  • Better locale support for numbers in Number helper
  • Test suite to fail louder if PHPUnit was not found
  • Small improvements to debug functions
  • Fixed issues in data validation when using beforeValidate callback to change internal model data
  • Improving reliability in page numbers links for PaginatorHelper
  • Increased compatibility with CentOS servers
  • Reduced chance of cache collision in internal method cache for DboSource
  • Fixed issues with default exception renderer and custom helpers
  • Allow Set::extract() to match null.
  • Small bugfixes in XmlView
  • Fixed bugs in Translate Behavior
  • Set session.gc_maxlifetime by default.
  • Fixed bugs in sessions when using long numeric keys in arrays

2.2

  • More descriptive diffs in web test runner for failed tests
  • Complete E_STRICT compliance
  • Bug fixes for CakeTime timezone support
  • Helpers can now be defined at configuration time for sending emails.
  • Console commands are now grouped by plugin, core and app shells are always listed last.
  • Fixed small issues with ModelValidator and improved performance

View the complete changelog available for 2.2.0 [1] and 2.1.4 [2]. Download a packaged release [3]

CakeFest 2012 is around the corner and we already expect awesome talks and workshops during the best PHP conference out there. If you haven’t booked your tickets yet, it’s about time your do, don’t miss your chance as we’re still offering early bird prices!!

As always, thanks to the friendly CakePHP community for the patches, documentation changes and new tickets. Without you there would be no CakePHP!

Links

published on Jul 1, 2012 12:00 AM

Read more

Active Record pattern for CakePHP

Active Record pattern for CakePHP

I wanted to build a state engine with CakePHP, and I realize that I needed a kind of Active Record pattern. So I first built a behavior that allows me to retrieve objects in place of associative arrays.

Installation

To download it: go to https://github.com/boutinb/Active-Record-for-CakePHP I have tested this only with cakePHP 2.x

  • Copy the ActiveRecordBehavior.php in your Behavior folder
  • Tell your model to use it: $actsAs = array(‘ActiveRecord’ => array())
  • When you use a find(‘all’) or find(‘first) function, add the option ‘activeRecord’ => true

I chose this way, because I did not want to retrieve always objects when a find function was called. But it is possible to use it in another way: add in the constructor of the behavior the option ‘allFind’ => true, and if you do not want an object after a find add ‘activeRecord’ => false (this possibility was not yet thouroughly tested: i’m afraid that cake generates sometimes a ‘find’ call that needs associative arrays).

How to use it

When you retrieve an object record, you can use it in this way: assume that you have the following models:

  • Post (title, message) belongsTo Writer, hasMany Comments, hasAndBelongsToMany Tags
  • Writer (name) hasMany Posts, belongsTo WriterGroup
  • WriterGroup (name) hasMany Writers
  • Comment (message) belongsTo Post
  • Tag (name) hasAndBelongsToMany Posts

Call find(‘first’) of find(‘all’) to retrieve the posts and with one post you can do the following:

  • $message = $post->message : this retrieves the message of the post
  • $post->message = ‘Hallo’ : this updates the message of the post
  • $writer = $post->Writer : this retrieves the writer ActiveRecord object
  • $comments = $post->Comments : this retrieves the ActiveRecordAssociation object

The Behavior makes a difference between belongsTo/hasOne associations and hasMany/hasAndBelongsToMany associations:

  • with belongsTo and hasOne associations, the ActiveRecord object pointed by the association is retrieved, and you can use it directly: e.g. $post->Writer->WriterGroup->name

  • with hasMany and hasAndBelongsToMany associations, the ActiveRecordAssociation object is retrieved. The class of this object implements the IteratorAggregate, Countable and ArrayAccess interfaces so that you can use it as an array:

    • foreach ($post->Comments as $comment) {}
    • count($post->Comments);
    • $comments = $post->Comments; $first_comment = $comments[0];

But also, the ActiveRecordAssociation class has 3 functions:

  • $comments->add($new_comment);
  • $comments->remove($first_comment);
  • $comments->replace($first_comment, $new_comment);

In order for the developer to clearly see the difference beween the 2 kinds of associations, I advice to use a plural name for hasMany and hasAndBelongsToMany associations, and singular name for hasOne and belongsTo associations.

Extend ActiveRecord class

Per default, the object you retrieve is of the class ActiveRecord. But you can of course extend this class for one model. Per default, the behavior will look for a class in the subfolder ModelActiveRecord with name ‘AR’, e.g.: ARPost or ARComment (the prefix ‘AR’ and the subfolder name can be changed in the bahavior constructor options). In the file ARPost.php:

 `

App::import('Model\Behavior','ActiveRecord');

classARTPostextendsActiveRecord{
public$var;
publicfunctionfunc(){...}
}

`

If you need to use the constructor:

 `
publicfunction__construct(array$record,array$options=array()){
parent::__construct($record,$options);
...
}

`

Then you can use $post->var and $post->func() in your code. You can also create new object:

 `
$post=newARPost(array(
'title'=>'Mytitle',
'message'=>'OK',
'Writer'=>$writer));

`

Here it becomes to be quite nice: in place of telling that the writer_id of the post should be ` $writer->id`, you can directly say ` ‘Writer’=>$writer` You can also do:

 `
$post->Comments=array($comment);

`

This will set automatically the ` $comment->post_id` to the right one.

Useful functions

I realize that when using hasMany (or hasOne association), when you do

 `

$post->Comments->remove($comment);
or
$post->Comments=null;

`

You want not only to remove the $comment from $post, but most of the time you want to delete $comment. I thought it would be quite handy if this is done automatically. For this, if you set in the association definition ‘deleteWhenNotAssociated’ to true, the behavior will automatically delete all records that are removed from the association.

The behavior offers also the possibility to delete, refresh and undo an ActiveRecord:

 `
$post->delete();//deletethispostrecord
$post->refresh();//querythevaluesofpostinthedatabase.
$post->undo();//undoallmodificationdoneinthe$postrecord.

`

The modifications done in the active records are not sent to the database. This is done only when calling the save() method. But $post->save() will only save the modification in the post record, not in its associated records. To save all modifications you made (explicitely and implicitely), use $post->saveAll() or ActiveRecord::saveAll() method Morevover saveAll() takes care that the records are saved in the right order. For example:

 `
$comment=newARComment(array('message'=>'Newmessage'));
$post=newARPost(array('title'=>'Newtitle','message'=>'NewMessage','Writer'=>$writer));
$post->Comment=array($comment);
ActiveRecord::saveAll();

`

Then saveAll() takes care that $post is created first so that its id can be set to $comment->post_id.

What is really nice with this Active Record pattern, is that you don’t need anymore to bother about the keys and how you should construct the associated arrays to be sure that cakePHP will save correctly your data (especially with hasAndBelongsToMany associations!)

Extending even more

I needed also a possiblility to have subclasses of ActiveRecord. For example I had an Action model, but I needed to define subclasses for each kind of action. A subclass action may use a (sub) model or not. For this I told the behavior to check whether the Model has the function getActiveRecordProperties(), and if yes it calls it before it builds a new ActiveRecord. This function tells the behavior what is the real ActiveAction name it must call, with which model and with which data. Here an example:

My model Action has a column type. This column will determine which kind of ActiveRecord class it must call. Then in the Action model, I have added this function:

 `
publicfunctiongetActiveRecordProperties(&$record){
$type=$record[$this->alias]['type'];
$active_record_name='AR'.$type.'Action';
$model=$this;
App::import('Model\ActiveRecord',$active_record_name);
returnarray('active_record_name'=>$active_record_name,'record'=>$record,'model'=>$model);
}

`

My ARAction looks like this:

 `
abstractclassARActionextendsAppActiveRecord{
abstractpublicfunctionexecute(ARUserState$user_state,$parameter);
}

`

The SendEmail subaction looks like that:

 `
classARSendEmailActionextendsARAction{
publicfunctionexecute(ARUserState$user_state,$parameter){
....
}
}

`

Then if I have a record in my Action table with type ‘SendEmail’, Action->find() returns an object of Class ARSendEmailAction. When calling execute(), it will call the right one that will send an email. Here the ARSendEmailAction uses the same model as ARAction, but if needed I could have set it to another one.

published on Jun 29, 2012 12:00 AM

Read more

Trello API wrapper plugin

Trello API wrapper plugin

Trello is useful tool for project management (see https://trello.com). This plugin provides model & datasource so you can comfortably search using standard CakePHP find method.

Get code from https://github.com/segy/TrelloApi. You can see a full description there.

published on Jun 27, 2012 12:00 AM

Read more

Simple 3rd-party provider authentication with Opauth plugin

Simple 3rd-party provider authentication with Opauth plugin

Opauth is a multi-provider authentication framework for PHP, inspired by OmniAuth for Ruby. Opauth enables PHP applications to perform user authentication across different providers with much ease & simplicity.

Implement Opauth easily on CakePHP

What is Opauth?

Opauth is a multi-provider authentication framework for PHP, inspired by OmniAuth for Ruby.

Opauth enables PHP applications to perform user authentication across different providers with much ease & simplicity.

Opauth interfaces between authentication providers’ API and your PHP applications through strategies. Strategies available for Opauth include Facebook, Google, Twitter, OpenID, and more.

Visit http://opauth.org for a quick demo.

Opauth on GitHub: uzyn/opauth Opauth as a Composer package: opauth/opauth

Opauth on CakePHP

Opauth is made even easier to be implemented on CakePHP applications through Opauth CakePHP plugin

Quick table of contents:

  • How to use this plugin (long and thorough)
  • A quick sample app (pre-configured CakePHP app, with screenshots )

How to use this plugin

  1. Download Opauth CakePHP plugin and place it at your CakePHP Plugin directory. Or via Git: Assuming ` APP` is the directory where your CakePHP app resides, it’s usually ` app/` from the base of CakePHP:

    cd APP/Plugin
    git clone git://github.com/uzyn/cakephp-opauth.git Opauth
    
    cd Opauth
    git submodule init
    git submodule update
    
  2. Add this line to the bottom of your app’s ` Config/bootstrap.php`:

    <?php
    CakePlugin::load('Opauth', array('routes' => true, 'bootstrap' => true));
    

    Overwrite any Opauth configurations you want after the above line.

  3. Load strategies onto Strategy/ directory. Append configuration for strategies at your app’s ` Config/bootstrap.php` as follows:

    <?php
    CakePlugin::load('Opauth', array('routes' => true, 'bootstrap' => true));
    
    // Using Facebook strategy as an example
    Configure::write('Opauth.Strategy.Facebook', array(
       'app_id' => 'YOUR FACEBOOK APP ID',
       'app_secret' => 'YOUR FACEBOOK APP SECRET'
    ));
    
  4. Go to http://path_to_your_cake_app/auth/facebook to authenticate with Facebook, and similarly for other strategies that you have loaded.

  5. After validation, user will be redirected to Router::url(‘/opauth-complete’) with validated auth response data retrievable available at $this->data. To route a controller to handle the response, at your app’s Config/routes.php, add a connector, for example:

    <?php
    Router::connect(
       '/opauth-complete/*',
       array('controller' => 'users', 'action' => 'opauth_complete')
    );
    

    You can then work with the authentication data at, say ` APP/Controller/UsersController.php` as follows:

    <?php // APP/Controller/UsersController.php:
    class UsersController extends AppController {
       public function opauth_complete() {
           debug($this->data);
       }
    }
    

    Note that this CakePHP Opauth plugin already does auth response validation for you with its results available as a boolean value at $this->data[‘validated’].

How about a sample?

Sure. Simply download this CakePHP app and set it up with CakePHP v2.x library.

Once it is set up, you should see: (Homepage screenshot)

After authentication, this is what you should be getting: (Callback screenshot)

More instructions on the sample app: https://github.com/uzyn/cakephp-opauth/tree/sample

See also

Issues & questions

published on Jun 25, 2012 12:00 AM

Read more

Manejo básico Cache FILE

Manejo básico Cache FILE

Un componente simple y corto que permite manejar las funciones básicas de caché, así veremos que nuestra aplicación tendrá un mejor rendimiento ‘File’, //[required] //’duration’=> 3600, //[optional] //’probability’=> 100, //[optional] ‘path’ => CACHE, //[optional] use system tmp directory - remember to use absolute path ‘prefix’ => ‘’, //[optional] prefix every cache file with this string ‘lock’ => false, //[optional] use file locking //’serialize’ => true, //[optional] )); Cache::write($nombre_cache, $data); return true; } function obtenerCache($nombre_cache = null){ $data = null; if(empty($nombre_cache)){ return $data; } $data = Cache::read($nombre_cache); return($data); } function borrarCache($nombre_cache = null){ if(!empty($nombre_cache)){ Cache::delete($nombre_cache); //return true; } } } ?> En el controlador var $components = array(‘Manejocache’); para borrar: $this->Manejocache->borrarCache(‘NOMBRECACHE’); para obtener cache: $this->Manejocache->obtenerCache(‘NOMBRECACHE’); para guardar cache: $this->Manejocache->guardarCache(‘NOMBRECACHE’);

published on Jun 25, 2012 12:00 AM

Read more

Javascript/CSS/LESS module loader + dependency calculator plugin("ResourcesController")

Javascript/CSS/LESS module loader + dependency calculator plugin(“ResourcesController”)

ResourcesController is a module loader for resource files (e.g. javascript, LESS, CSS). It can handle both inter- and intra- package dependencies, as well as a variety of preprocessors (I have currently only put a LESS CSS preprocessor in, but others can be easily built using the implementable iPreprocessor interface).

(You can find it at https://github.com/gfarrell/ResourcesController - please fork it and improve it!)

I have always found it pretty frustrating when one has loads of nicely separated javascript files, each with its own class and each with its own dependencies but then you have to either run a compiler of some sort to mash them all together (like Juicer or BTMPackager) or use a client side asynchronous module loader like require.js.

ResourcesController allows you to define packages of files like CSS, LESS or Javascript files with dependencies either for the whole package or for the individual file and then when the files are requested the dependency tree is flattened and the files are packaged up, compressed and delivered.

The plugin also uses caching (otherwise this would be a really slow operation) so that if the files haven’t changed since the last cache, the cached version is served up. The best part of that is that it uses native Cake caching so whatever your chosen cache engine, it’s already using it!

At the moment it can do CSS and Javascript compression and LESS preprocessing. I wanted to include CoffeeScript but there’s no PHP version and I am loathe to use exec() commands in a generally available plugin. I wanted this to be as versatile as possible.

It’s pretty easy to extend, you can just write new preprocessor components with the iPreprocessor interface.

The documentation should be quite complete, so have a look and let me know if you use it/what you think/if you encounter bugs.

(You can find it at https://github.com/gfarrell/ResourcesController - please fork it and improve it!)

published on Jun 22, 2012 12:00 AM

Read more

Sending content to the layout using Cake 2.x

Sending content to the layout using Cake 2.x

This post is based on Robert Conner’s code for CakePHP 1.x., and I made some changes to get it to work on CakePHP 2.x and add some explanations on how to use it. The original post is on http://bakery.cakephp.org/articles/rtconner/2007/08/28 /anything_for_layout-making-html-from-the-view-available-to-the-layout Maybe many people have faced the problem for sending some content to the layout on CakePHP. By saying content I mean not only a simple string but a whole a piece of HTML code. To solve this, we can create a Helper on CakePHP 2.x, according to the following steps:

1. Create the Helper

On the Views/Helpers folder, you need to create the .php file for the helper. In this case we will call it LayoutHelper.php

class LayoutHelper extends AppHelper {

 var $__blockName = null;

 function blockStart($name) {
 if (empty($name)) trigger_error('LayoutHelper::blockStart - name is a required parameter');
 if (!is_null($this->__blockName))
 trigger_error('LayoutHelper::blockStart - Blocks cannot overlap');
 $this->__blockName = $name; ob_start();
 return null;
 }

 function blockEnd(&$view) {
 $buffer = @ob_get_contents();
 @ob_end_clean();
 $out = $buffer;
 $view->viewVars[$this->__blockName . '_for_layout'] = $out; $this->__blockName = null;
}

function output($var) {
 if (isset($var) && $var != null)
 echo $var;
 }
 }

2. Setting up the content

For setting up the content that we want to send to the layout, we use the Helper

$layout = $this->Helpers->load('Layout');
$layout->blockStart('custom_content');

right after this, we specify the content that will be sent to the layout

<div>
Custom content
</div>

and we close the block

$layout->blockEnd($this);

3. Show the content

For showing the content on the layout, we add the following

$layout = $this->Helpers->load('Layout');
$layout->output($custom_content_for_layout);

As we can see, this is really simple and also very useful when trying to customize the content on the layout according to the view we are loading

published on Jun 20, 2012 12:00 AM

Read more

Composer Plugin for CakePHP

Composer Plugin for CakePHP

Use Composer conveniently with your CakePHP application and get access to a vast library of reusable PHP components and packages through Packagist.

About Composer

Composer is a tool for dependency management in PHP. It allows you to declare the dependent libraries your project needs and it will install them in your project for you.

With Packagist, you get access to a vast library of reusable PHP components that will help a lot in your development work.

About this plugin

This is a CakePHP plugin to use Composer conveniently with your CakePHP 2.x project.

There is no need to pre-install Composer. This plugin will automatically download the latest version if Composer is not installed at your system.

Packages downloaded via this Composer plugin will be installed at ` APP/Vendor` as per CakePHP convention.

Quick links

How to use

  1. Download the plugin and place it at ` APP/Plugin/Composer`. Or via Git:
cd APP/Plugin
git clone git://github.com/uzyn/cakephp-composer.git Composer
  1. Load the plugin by adding this line to the bottom of your app’s ` Config/bootstrap.php`:
<?php
CakePlugin::load('Composer', array('bootstrap' => true));
  1. That’s all! Composer is ready for use. ` composer.json` is located at ` APP/composer.json`. It is automatically created if it is not found. Packages are installed to ` APP/Vendor` as per CakePHP convention. Invoke Composer from command line with ` Console/cakecomposer.c`. For example, to install opauth/opauth using Composer’s ` require` command.
 cd APP
 Console/cake composer.c require opauth/opauth:0.*

To install packages defined at ` composer.json`
Console/cake composer.c install
  1. This plugin also makes use of Composer’s autoloader. Start using a Composer-loaded classes right away without needing ` require()`, ` include()` or ` App::import()`. For example, to instantiate a new Opauth object, simply instantiate Opauth from anywhere (model, controller, view, literally anywhere) in your CakePHP application:
<?php
$Opauth = new Opauth();

Issues & questions

published on Jun 20, 2012 12:00 AM

Read more

CakePHP 2.2.0-RC2

CakePHP 2.2.0-RC2

The CakePHP team is proud to announce the immediate availability of CakePHP 2.2.0-RC2, the final Release Candidate for this branch.

A bit later than expected, but charged with new awesome features and stability, CakePHP 2.2.0-RC2 finally lands for a final test-drive before it’s marked stable. As mentioned in previous releases, 2.2.x will be an API compatible release with 2.0.x, and 2.1.x and should be generally transparent when upgrading, except for a few additions you need to make in configuration files.

We let a few new features sneak into this release as we considered them safe and useful enough to our community. A quick list of new features added in 2.2.0-RC2:

Validation

A few new methods were added to the Validation class: naturalNumber, uploadError and mimeType. Natural number validation is used in case you want a numeric validation but only for non-negative numbers. Upload related methods were added to make it easier for models to correctly validate uploaded files, specifically mimeType method will validate the correct mimetype for files without relying on file extension.

Bake

Several small enhancements were added to improve experience of baking test cases and new plugins. For instance, creating a new plugin will automatically configure it in bootstrap.php

CakeRequest

PUT and DELETE methods’ payload data will now be placed into $request->data if it is encoded correctly. This makes it easier for controllers to implement actions transparently without taking explicit actions for each of those methods.

Misc Changes

  • session.gc_maxlifetime is now set when using files for sessions. This prevents session files from being garbage collected too early.
  • cake i18n extract now has an –overwrite option to force overwriting all existing pot files.
  • App::uses() now supports namespaced classes better.
  • belongsTo and hasOne associations should generate fewer queries when recursive > 1.
  • TranslateBehavior::unbindTranslation() works as documented now.
  • HtmlHelper::tableHeaders() now accepts HTML attributes for each cell.
  • Router::setExtensions() was added to allow new extensions to be added instead of replacing all existing extensions.
  • Security::rijndael() was added and exposed to CookieComponent. This allows strong encryption to be used, and is recommended for all applications using ciphered cookies.
  • The datasource method cache is now more resistant to collisions.
  • Email templates using images now work correctly more often.
  • app/Console/cake now correctly determines the app directory in more situations.
  • PUT and DELETE requests with application/www-form-urlencoded data are now automatically parsed and set as $this->data in the request object.
  • Session cookies are now httpOnly by default.
  • All validation errors are returned when saving/validating associated models if the primary model’s validation fails.

View the complete changelog available [1]. Download a packaged release [2]

CakeFest 2012 is around the corner and we already expect awesome talks and workshops during the best PHP conference out there. If you haven’t booked your tickets yet, it’s about time your do.

As always, thanks to the friendly CakePHP community for the patches, documentation changes and new tickets. Without you there would be no CakePHP!

Links

published on Jun 20, 2012 12:00 AM

Read more

Email template management plugin

Email template management plugin

Hi everyone, This is my first open source plugin. which we can use to manage email templates in cakephp

Just to provice a little breath of relief to every Cake baker out there, here is a solution for creating and updating email content as per requirement of client every time to time. The objective is to skip the amount of effort of developer from every time email content changes according to the requirement. This Plugin will help administrator to change email content as per there requirement and need, whenever it is needed,

How to use?

1) Download (https://github.com/madhavi- webonise/email_template/downloads ) or clone (https://github.com /madhavi-webonise/email_template ) the code for this plugin .

2) Add the email_template folder into your “your-app-path/app/plugins” folder.

3) Run the migration to create required table. Migration will add one dummy email template in your database table.

  1. Now check the email templates list in your application.

5) You can add more email templates from “your-app- url/email_template/email_templates/add”.

6) you can check Constants list which you can use into email content to replace by real value by clicking “Email Constants” link from add or edit page.

7) you can add more constants in “$emailconstants” array from EmailTemplateAppController with blank value. If we didn’t provide for any constant in code then it will replace with black and it will not show direct constant in email.

8) You can add same constant in “EmailTemplateController” with there one or two lines description Where and why we can use that constant.

9) Now In code where you have to use the email template fetch it from database by there slug name and Replace the constants with there valid values to how to do this check “getEmailTemplateAndReplaceConstant” action from “EmailTemplateController”.

  1. Send the email using email templates.

for any further queries or suggestions, please write me to madhavi [at] weboniselab.com.

published on Jun 11, 2012 12:00 AM

Read more

An Automated tool for creating ACOs for CakePHP 2

An Automated tool for creating ACOs for CakePHP 2

There was a tool(code) for CakePHP 1.3 for creating ACOs automatically (http://book.cakephp.org/1.3/view/1549/An-Automated-tool-for-creating- ACOs). It didn’t work on 2.1 though. I made a few fixes so it seems to work fine (I haven’t tested it throughout and doubt that it’s bulletproof, but it did what I wanted it to do). Hope someone will find it useful.

function build_acl() {
    if (!Configure::read('debug')) {
        return $this->_stop();
    }
    $log = array();

    $aco = & $this->Acl->Aco;
    $root = $aco->node('controllers');
    if (!$root) {
        $aco->create(array('parent_id' => null, 'model' => null, 'alias' => 'controllers'));
        $root = $aco->save();
        $root['Aco']['id'] = $aco->id;
        $log[] = 'Created Aco node for controllers';
    } else {
        $root = $root[0];
    }

    App::uses('File', 'Utility');
    $ControllersFresh = App::objects('Controller');

    foreach ($ControllersFresh as $cnt) {
        $Controllers[] = str_replace('Controller', '', $cnt);
    }
    $appIndex = array_search('App', $Controllers);
    if ($appIndex !== false) {
        unset($Controllers[$appIndex]);
    }
    $baseMethods = get_class_methods('Controller');
    $baseMethods[] = 'build_acl';

    $appcontr = get_class_methods('AppController');

    foreach ($appcontr as $appc) {
        $baseMethods[] = $appc;
    }

    $baseMethods = array_unique($baseMethods);

    $Plugins = $this->_getPluginControllerNames();
    $Controllers = array_merge($Controllers, $Plugins);

    // look at each controller in app/controllers
    foreach ($Controllers as $ctrlName) {
        $methods = $this->_getClassMethods($this->_getPluginControllerPath($ctrlName));

        // Do all Plugins First
        if ($this->_isPlugin($ctrlName)) {
            $pluginNode = $aco->node('controllers/' . $this->_getPluginName($ctrlName));
            if (!$pluginNode) {
                $aco->create(array('parent_id' => $root['Aco']['id'], 'model' => null, 'alias' => $this->_getPluginName($ctrlName)));
                $pluginNode = $aco->save();
                $pluginNode['Aco']['id'] = $aco->id;
                $log[] = 'Created Aco node for ' . $this->_getPluginName($ctrlName) . ' Plugin';
            }
        }
        // find / make controller node
        $controllerNode = $aco->node('controllers/' . $ctrlName);
        if (!$controllerNode) {
            if ($this->_isPlugin($ctrlName)) {
                $pluginNode = $aco->node('controllers/' . $this->_getPluginName($ctrlName));
                $aco->create(array('parent_id' => $pluginNode['0']['Aco']['id'], 'model' => null, 'alias' => $this->_getPluginControllerName($ctrlName)));
                $controllerNode = $aco->save();
                $controllerNode['Aco']['id'] = $aco->id;
                $log[] = 'Created Aco node for ' . $this->_getPluginControllerName($ctrlName) . ' ' . $this->_getPluginName($ctrlName) . ' Plugin Controller';
            } else {
                $aco->create(array('parent_id' => $root['Aco']['id'], 'model' => null, 'alias' => $ctrlName));
                $controllerNode = $aco->save();
                $controllerNode['Aco']['id'] = $aco->id;
                $log[] = 'Created Aco node for ' . $ctrlName;
            }
        } else {
            $controllerNode = $controllerNode[0];
        }

        //clean the methods. to remove those in Controller and private actions.
        foreach ($methods as $k => $method) {
            if (strpos($method, '_', 0) === 0) {
                unset($methods[$k]);
                continue;
            }
            if (in_array($method, $baseMethods)) {
                unset($methods[$k]);
                continue;
            }
            $methodNode = $aco->node('controllers/' . $ctrlName . '/' . $method);
            if (!$methodNode) {
                $aco->create(array('parent_id' => $controllerNode['Aco']['id'], 'model' => null, 'alias' => $method));
                $methodNode = $aco->save();
                $log[] = 'Created Aco node for ' . $method;
            }
        }
    }
    if (count($log) > 0) {
        debug($log);
    }

    exit;
}

function _getClassMethods($ctrlName = null) {
    if($this->_isPlugin($ctrlName)){
        App::uses($this->_getPluginControllerName ($ctrlName), $this->_getPluginName ($ctrlName). 'Controller');
    }
    else
        App::uses($ctrlName . 'Controller', 'Controller');


    if (strlen(strstr($ctrlName, '.')) > 0) {
        // plugin's controller
        $ctrlName = str_replace('Controller', '', $this->_getPluginControllerName ($ctrlName));
    }
    $ctrlclass = $ctrlName . 'Controller';
    $methods = get_class_methods($ctrlclass);

    // Add scaffold defaults if scaffolds are being used
    $properties = get_class_vars($ctrlclass);
    if (array_key_exists('scaffold', $properties)) {
        if ($properties['scaffold'] == 'admin') {
            $methods = array_merge($methods, array('admin_add', 'admin_edit', 'admin_index', 'admin_view', 'admin_delete'));
        } else {
            $methods = array_merge($methods, array('add', 'edit', 'index', 'view', 'delete'));
        }
    }
    return $methods;
}

function _isPlugin($ctrlName = null) {
    $arr = String::tokenize($ctrlName, '.');
    if (count($arr) > 1) {
        return true;
    } else {
        return false;
    }
}

function _getPluginControllerPath($ctrlName = null) {
    $arr = String::tokenize($ctrlName, '/');
    if (count($arr) == 2) {
        return $arr[0] . '.' . $arr[1];
    } else {
        return $arr[0];
    }
}

function _getPluginName($ctrlName = null) {
    $arr = String::tokenize($ctrlName, '.');
    if (count($arr) == 2) {
        return $arr[0];
    } else {
        return false;
    }
}

function _getPluginControllerName($ctrlName = null) {
    $arr = String::tokenize($ctrlName, '/');
    if (count($arr) == 2) {
        return $arr[1];
    } else {
        return false;
    }
}

/**
 * Get the names of the plugin controllers ...
 *
 * This function will get an array of the plugin controller names, and
 * also makes sure the controllers are available for us to get the
 * method names by doing an App::import for each plugin controller.
 *
 * @return array of plugin names.
 *
 *
 */
function _getPluginControllerNames() {
    App::uses('Folder', 'Utility');
    $folder = & new Folder();
    $folder->cd(APP . 'Plugin');

    // Get the list of plugins
    $Plugins = $folder->read();
    $Plugins = $Plugins[0];
    $arr = array();

    // Loop through the plugins
    foreach ($Plugins as $pluginName) {
        // Change directory to the plugin
        $didCD = $folder->cd(APP . 'Plugin' . DS . $pluginName . DS . 'Controller');
        if ($didCD) {
            // Get a list of the files that have a file name that ends
            // with controller.php
            $files = $folder->findRecursive('.*Controller\.php');

            // Loop through the controllers we found in the plugins directory
            foreach ($files as $fileName) {
                // Get the base file name
                $file = basename($fileName);

                // Get the controller name
                //$file = Inflector::camelize(substr($file, 0, strlen($file) - strlen('Controller.php')));
                if (!preg_match('/^' . Inflector::humanize($pluginName) . 'App/', $file)) {
                    $file = str_replace('.php', '', $file);

                    /// Now prepend the Plugin name ...
                    // This is required to allow us to fetch the method names.
                    $arr[] = Inflector::humanize($pluginName) . "." . $file;
                }

            }
        }
    }


    return $arr;

}

published on Jun 11, 2012 12:00 AM

Read more

Very helpful plugin for Beginners and Experts

Very helpful plugin for Beginners and Experts

I have launched a new version(1.1) of my plugin for user management. Demo at http://umpremium.ektasoftwares.com

This plugin is Basic need of your website. Basically It gives you all features which you need on starting your website or a project in cakephp 2.x framework.

It is very helpful for Beginners because of following features-

  1. Clean code with coding standards
  2. Proper documentations
  3. Newbie will learn- a. How to write code in Cakephp? b. How to use CSRF/XSS protection in cakephp c. How to use SSL/HTTPS in cakephp for whole site as well as only some pages. d. How to use Ajax Pagination in cakephp. e. How to use Ajax Form Validations with File/Image in cakephp.

and many more. For all features,Beginners please have a look on http://developers.ektasoftwares.com/docs/umpremium/beginners.html

  1. Experts will also learn many other things. For all features http://umpremium.ektasoftwares.com

You can start your project or a website in few minutes with this plugin because this plugin has all things which you can think in starting of your project.

The main features are-

  1. Login with Facebook, Twitter, Linkedin, Four Square, Gmail, Yahoo.
  2. All Configurations are database driven. No need to touch php code for config setting.
  3. No need to hard code your site URL any where.
  4. View Online users and guest and admin can take many action on online users.
  5. SSL support for selected pages or whole site.
  6. Most of the things are Ajax driven.

I cannot describe all features here so please have a look on demo at http://umpremium.ektasoftwares.com here you can find all features of this plugin.

published on Jun 6, 2012 12:00 AM

Read more

Jquery search ajax pagination

Jquery search ajax pagination

This is my first article, i’ve been working on this very component to build dynamics conditions for paginates based on the data entered in a form on the index page.

The component, create file build_conditions.php

<?php
/**
 *
 * Build conditions for search
 * @author Geneller Naranjo
 * @version 1.0
 * @license This content is released under the MIT License (http://www.opensource.org/licenses/mit-license.php)
 *
 */
class BuildConditionsComponent extends Object {

    function initialize(&$controller) {
        $this->controller =& $controller;
    }

    function startup(&$controller) {    }


    /**
     *
     * Funcion que arma las condiciones para los buscadores.
     * Tener cuidado, solo usar para listados que usan el like como comparador.
     * @param Strin $modelName Modelo con las condiciones.
     */
    function buildConditions($modelName) {
        $conditions = array();
        foreach ($this->controller->data['Search'] as $field => $value) {
            if(!empty($value)) {
                if(substr($field, -3, 3) == '_id') {
                    $conditions["$modelName.$field"] = $value;
                } else {
                    $conditions[] = "$modelName.$field like '$value%'";
                }
            }
        }
        return $conditions;
    }

    /**
     *
     * Funcion que arma las condiciones para los buscadores.
     * Tener cuidado, solo usar para listados que usan el like como comparador.
     * Arma las condiciones dependiendo de los campos del formulario.
     */
    function buildComplexConditions() {
        $conditions = array();
        foreach ($this->controller->data['Search'] as $model => $fields) {
            foreach ($fields as $field => $value) {
                if(!empty($value)) {
                    if(substr($field, -3, 3) == '_id') {
                        $conditions["$model.$field"] = $value;
                    } else {
                        $conditions[] = "$model.$field like '$value%'";
                    }
                }
            }
        }
        return $conditions;
    }

}
?>

Create a file jquery.paginate_form.js under webroot/js/.

/**
 *
 * Triggers search
 * @author Geneller Naranjo
 * @version 1.0
 * @license This content is released under the MIT License (http://www.opensource.org/licenses/mit-license.php)
 *
 */
// Teclas que no deben disparar la busqueda.
var unavailableKeyCodes = [9, 13, 16, 17, 18, 19, 20, 27, 35, 36, 37, 38, 39, 40, 45, 93, 106, 107, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 144, 145, 186, 187, 189, 190, 191, 192, 219, 220, 221, 222];

// Variables para abortar peticiones ajax.
var requesting = true;
var request = new $.ajax();
var focused = '';

function paginator(url, domId, targetDomId) {
    var ajaxDelay = 8;
    var params = {};

    function paginate(params) {
        if(requesting == true) {
            request.abort();
        }
        if(typeof(params.url) != 'undefined') {
            url = params.url;
        }
        request = $.ajax({
            data: params.data,    type: 'post',    async: true,    url: url,
            beforeSend: function() {requesting = true;    },
            complete: function(data) {
                $('#' + targetDomId).html(data.responseText);
                requesting = false;
            }
        });
    }

    setInterval(function() {
        ajaxDelay++;
        if(ajaxDelay == 8) {
            params.data = $('#' + domId).serialize();
            paginate(params);
        }}, 100);

    $('#' + domId + ' div input').keyup(function(e) {
        if(requesting == true) {
            request.abort();
        }
    });

    $('#' + domId + ' div input').keyup(function(e) {
        delete params.url;
        if(unavailableKeyCodes.indexOf(e.keyCode) == -1) {
            if(typeof(e.currentTarget.attributes[1].nodeValue) != 'undefined') {
                focused = e.currentTarget.attributes[1].nodeValue;
            }
            ajaxDelay = 1;
        }
    });

    $('#' + domId + ' div select').change(function(e) {
        params.data = $('#' + domId).serialize();
        paginate(params);
    });

    $('#' + domId + ' div input:checkbox').change(function(e) {
        params.data = $('#' + domId).serialize();
        paginate(params);
    });

    $('#' + domId).submit(function() {
        delete params.url;
        params.data = $('#' + domId).serialize();
        paginate(params);
        return false;
    });

    $('#' + targetDomId + ' .paging a').live('click', function(e) {
        e.preventDefault();
        delete params.url;
        params.data = $('#' + domId).serialize();
        var href = $(this).attr('href');
        params.url = href.replace('index/', 'index_ajax/');
        paginate(params);
    });

    $('#' + targetDomId + ' table th a').live('click', function(e) {
        e.preventDefault();
        delete params.url;
        params.data = $('#' + domId).serialize();
        var href = $(this).attr('href');
        params.url = href.replace('index/', 'index_ajax/');
        paginate(params);
    });

}

in your view (i suppose the index) put this.

<?php echo $javascript->link('jquery.paginate_form'); ?>
<script type="text/javascript">
$(function() {
    paginator('<?php echo $this->base . '/<controller>/<action>'?>', 'SearchIndexForm', 'indexAjax');

});
</script>

This is an html sample code for the index.

<div class="header">
        <h2>Carrocerías</h2>
    </div>
    <div id="hideableSearch">
        <div id="showSearchImages">
<?php
echo $html->image('Search-index.png', array('style'=>'height: 35px;'));
?>
        </div>
        <div id="searchFormDiv">
            <fieldset class="fieldset-search-index">
<?php
echo $form->create('Search', array('id'=>'SearchIndexForm', 'encoding'=>'UTF-8'));
echo $form->input('nombre', array('type'=>'text', 'size'=>10));
echo $form->input('codigo', array('type'=>'text', 'size'=>10));
echo $form->input('descripcion', array('type'=>'text', 'size'=>20));
echo $form->end();
?>
            </fieldset>
        </div>
    </div>
<div id="indexAjax">
<table cellpadding="0" cellspacing="0">
    <tr>
        <th>#</th>
        <th><?php echo $this->Paginator->sort('Nombre','nombre', array('url'=>$url));?></th>
        <th><?php echo $this->Paginator->sort('Codigo','codigo', array('url'=>$url));?></th>
        <th><?php echo $this->Paginator->sort('Descripcion','descripcion', array('url'=>$url));?></th>
        <th class="actions">Acciones</th>
    </tr>
<?php
$i = 0;
foreach ($carrocerias as $item):
    $class = null;
    if ($i++ % 2 == 0) $class = ' class="altrow"';
?>
    <tr<?php echo $class; ?> id="<?php echo $item['Carroceria']['id']?>">
        <td><?php echo $i; ?> </td>
        <td><?php echo $item['Carroceria']['nombre']; ?> </td>
        <td><?php echo $item['Carroceria']['codigo']; ?> </td>
        <td><?php echo $item['Carroceria']['descripcion']; ?> </td>
        <td class="actions">
            <?php echo $this->Html->link($html->image('Edit.png'), array('action' => 'edit', $item['Carroceria']['id']), array('escape'=>false, 'class'=>'index-actions')); ?>
        </td>
    </tr>
<?php endforeach; ?>
</table>
<p>
<?php
echo $this->Paginator->counter(array(
'format' => 'Pag %page% de %pages%, %current% registros de %count% en total, desde %start% hasta %end%'
));
?></p>
<div class="paging">
<?php
$paginator->options(array('url'=> $url));
echo $this->Paginator->prev('<< '.'Prev', array(), null, array('class'=>'disabled')).' | ';
echo $this->Paginator->numbers() .' | ';
echo $this->Paginator->next('Sig'.' >>', array(), null, array('class' => 'disabled'));
?></div>
</div>

The code in your view should be the answer you want into #indexAjax

In your controller should be something like

var $components = array('BuildConditions');

And the funcion you said in the url of the request, for this example “carrocerias/index_ajax”

function index_ajax() {
    $this->Carroceria->recursive = 0;
    $this->layout = 'ajax';
    $conditions = $this->BuildConditions->buildConditions($this->modelClass);
    $this->set('carrocerias', $this->paginate(null, $conditions));
}

for simple conditions, if you would create conditions for different models you should use “buildComplexConditions” instead of “buildConditions”.

I hope i made myself clear, please comment and let me know any issue or how to make better this component.

I hope i made myself clear, please comment and let me know how to fix any issue like the first u

published on May 31, 2012 12:00 AM

Read more

Markdown plugin for CakePHP 2.+

Markdown plugin for CakePHP 2.+

Can be used to convert markdown to HTML markup. It may be useful, for example, to create a help session in a system. That way you can also put your help files on github which also has an interpreter of markdown files.

Installation

You can clone the plugin into your project (or if you want you can use as a submodule):

cd path/to/app/Plugin or /plugins
git clone https://github.com/maurymmarques/markdown-cakephp.git Markdown

Bootstrap the plugin in app/Config/bootstrap.php:

CakePlugin::load(array('Markdown' => array('bootstrap' => true)));

Usage

Enable the helper using the plugin syntax If desired, set the component to assist with the return of data from the markdown.

// in app/Controller/BakeriesController.php
class BakeriesController extends AppController {

        public $helpers = array('Markdown.Markdown');
        public $components = array('Markdown.Markdown');

        public function index() {
            $this->set('textInMarkdownFormat', $this->Markdown->getFile($pathToFile));
        }
}

In the view you can use something like:

// in app/View/Bakeries/index.ctp
echo $this->Markdown->transform($textInMarkdownFormat);

GitHub

https://github.com/maurymmarques/markdown-cakephp

published on May 23, 2012 12:00 AM

Read more

CakePHP 2.1.3 & 2.2.0-RC1 released

CakePHP 2.1.3 & 2.2.0-RC1 released

The CakePHP core team is proud to announce the immediate availability of both CakePHP 2.1.3 [1], and 2.2.0-RC1[2]. 2.1.3 is a bugfix release for the 2.1.x branch, while 2.2.0-RC1 is the first release candidate for 2.2.x.

The CakePHP core team is proud to announce the immediate availability of both CakePHP 2.1.3 [1], and 2.2.0-RC1[2]. 2.1.3 is a bugfix release for the 2.1.x branch, while 2.2.0-RC1 is the first release candidate for 2.2.x.

CakePHP 2.1.3

There are a number of bugfixes in 2.1.3, the most notable of these changes are:

  • ControllerTestCase no longer overwrites GET/POST when simulating requests.
  • Xml::fromArray() now properly handles out of sequence numeric keys.
  • TranslateBehavior and Model::saveAll() now correctly save translations in hasMany associations.
  • Router::queryString() now correctly handles appending to existing querystrings.
  • Model::saveMany(), saveAssociated() correctly save data that was modified in a beforeValidate() callback.
  • View now correctly re-uses the Controller event manager instance.
  • Model::saveAll() and default values now behave better.

You can download a packaged release from http://pear.cakephp.org or get a zip file from github[3].

CakePHP 2.2.0-RC1

Since the release of CakePHP 2.2.0-beta a number of new features and enhancements have been merged in:

Timezone support in CakeTime class

The $userOffset parameter has been replaced with $timezone parameter in all relevant functions. So instead of numeric offset you can now pass in a timezone string or DateTimeZone object. Passing numeric offsets for $timezone parameter is still possible for backwards compatibility.

CakeTime::timeAgoInWords() had the accuracy option added. This option allows you to specify how accurate formatted times should be.

A few new methods were added:

  • CakeTime::toServer()
  • CakeTime::timezone()
  • CakeTime::listTimezones()

The $dateString parameter in all methods now accepts a DateTime object. A new config parameter ‘Config.timezone’ is available which you can set to user’s timezone string.

Dynamically modify and create validation rules

A new object ModelValidator was added to delegate the work of validating model data, it should be transparent to the application and fully backwards compatible. It also exposes a rich API to add, modify and remove validation rules. Check docs for this object in http://book.cakephp.org/2.0/en/models/data-validation.html#dynamically-change-validation-rules

Generate config files on the fly

Configure::dump() was added. It is used to persist configuration data in durable storage like files. Both PhpReader and IniReader work with it.

CakeLog

The CakeLog class now accepts the same log levels as defined in RFC 5424. Several convenience methods have also been added in CakeLog class:

  • emergency
  • alert
  • critical
  • error
  • warning
  • notice
  • info
  • debug

Also log engines gained a scope setting to make them log only the contexts they are interested in. You need to add the following lines to your Config/bootsrap.php file:

// Add logging configuration.
CakeLog::config('debug', array(
    'engine' => 'FileLog',
    'types' => array('notice', 'info', 'debug'),
    'file' => 'debug',
));
CakeLog::config('error', array(
    'engine' => 'FileLog',
    'types' => array('warning', 'error', 'critical', 'alert', 'emergency'),
    'file' => 'error',
));

Misc changes

  • FormHelper::inputDefaults() setter/getter added.
  • Added ability for Auth login to use contain.
  • Supported Japanese legacy charset and changed to use upper case charset in Content-Type line in CakeEmail.
  • Improved doc blocks in all functions, mixed params now explicitly say which types are accepted.

Links

published on May 23, 2012 12:00 AM

Read more

ZaakPay payment gateway component

ZaakPay payment gateway component

This is another component that is get used for ZaakPay payment gateway.

Some info about zaak pay : http://www.zaakpay.com/ Zaak pay is the payment gateway that operate inside india. It is very easy to integrate this payment gateway with your e-commerce application. There are some steps that you need to follow,

Register to Zaakpay : https://www.zaakpay.com/sign-up
After creating account, login to the customer panel.
Here you need to provide some information about your business.
From My Account go to Integration section.
On the 1st step you can configure the

    your application URLs to get the response back from the zaakpay.
    You can get the Merchant identifier & secret key that to be configured in your application

2nd step is to configure the limits for the transaction
3rd screen : you can customize a button that you want to use on your site.
4th step : UI on zaakpay page , you can configure

    headings, logo for the payment gateway page

You can use the current account as a test account, until you provide your business details to zaak pay & zaakpay approves it.

Zaakpay provides an SDK for PHP, but we modified the SDK & created our own component for the same.

Component : This is another component that is get used for ZaakPay payment gateway.

For using this component please follow following steps,

Create a ZaakPay.php inside app/Controller/Component/
Copy paste the below code in this file
Create a controller payments.php
Create views

ZaakPay Componenet :

<?php class ZaakPayComponent extends Object { public $config;

public function initialize($controller)
{
       $this->config = array(‘SiteName’ => ‘your_site_name’, ‘ZaakSecret’ => ‘secret_key_from_zaak_pay’, ‘ZaakMerchantIdentifier’ => ‘merchant_identifier_from_zaak_pay’);
}

function startup(&$controller)
{
   $this->controller =& $controller;

}

public function beforeRender()
{
}

public function shutdown()
{
}

public function beforeRedirect()
{
}

public function getOrderId()
{
   return $this->config['SiteName'] . time();
}

public function calculateChecksum($all)
{
   $hash = hash_hmac('sha256', $all, $this->config['ZaakSecret']);
   $checksum = $hash;
   return $checksum;
}


public function getAllParams()
{
   //ksort($_POST);
   $all = '';
   foreach ($_POST as $key => $value) {
       if ($key != 'submit') {
           if ($key != 'checksum') {
               $all .= "'";
               if ($key == 'returnUrl') {
                   $all .= $this->sanitizedURL($value);
               } else {
                   $all .= $this->sanitizedParam($value);
               }
               $all .= "'";
           }
       }
   }
   return $all;
}

public function outputForm($checksum)
{
   //ksort($_POST);
   $html = '';
   foreach ($_POST as $key => $value) {
       if ($key != 'submit') {
           if ($key == 'returnUrl') {
               $html .= '<input type="hidden" name="' . $key . '" value="' . $this->sanitizedURL($value) . '" />' . "\n";
           } else {
               $html .= '<input type="hidden" name="' . $key . '" value="' . $this->sanitizedParam($value) . '" />' . "\n";
           }
       }
   }
   $html .= '<input type="hidden" name="checksum" value="' . $checksum . '" />' . "\n";

   return $html;
}

public function verifyChecksum($checksum, $all)
{
   $cal_checksum = $this->calculateChecksum($all);
   $bool = 0;
   if ($checksum == $cal_checksum) {
       $bool = 1;
   }

   return $bool;
}

public function sanitizedParam($param)
{
   $pattern[0] = "%,%";
   $pattern[1] = "%#%";
   $pattern[2] = "%\(%";
   $pattern[3] = "%\)%";
   $pattern[4] = "%\{%";
   $pattern[5] = "%\}%";
   $pattern[6] = "%<%";
   $pattern[7] = "%>%";
   $pattern[8] = "%`%";
   $pattern[9] = "%!%";
   $pattern[10] = "%\\$%";
   $pattern[11] = "%\%%";
   $pattern[12] = "%\^%";
   $pattern[13] = "%=%";
   $pattern[14] = "%\+%";
   $pattern[15] = "%\|%";
   $pattern[16] = "%\\\%";
   $pattern[17] = "%:%";
   $pattern[18] = "%'%";
   $pattern[19] = "%\"%";
   $pattern[20] = "%;%";
   $pattern[21] = "%~%";
   $pattern[22] = "%\[%";
   $pattern[23] = "%\]%";
   $pattern[24] = "%\*%";
   $pattern[25] = "%&%";
   $sanitizedParam = preg_replace($pattern, "", $param);
   return $sanitizedParam;
}

public function sanitizedURL($param)
{
   $pattern[0] = "%,%";
   $pattern[1] = "%\(%";
   $pattern[2] = "%\)%";
   $pattern[3] = "%\{%";
   $pattern[4] = "%\}%";
   $pattern[5] = "%<%";
   $pattern[6] = "%>%";
   $pattern[7] = "%`%";
   $pattern[8] = "%!%";
   $pattern[9] = "%\\$%";
   $pattern[10] = "%\%%";
   $pattern[11] = "%\^%";
   $pattern[12] = "%\+%";
   $pattern[13] = "%\|%";
   $pattern[14] = "%\\\%";
   $pattern[15] = "%'%";
   $pattern[16] = "%\"%";
   $pattern[17] = "%;%";
   $pattern[18] = "%~%";
   $pattern[19] = "%\[%";
   $pattern[20] = "%\]%";
   $pattern[21] = "%\*%";
   $sanitizedParam = preg_replace($pattern, "", $param);
   return $sanitizedParam;
}

public function outputResponse($bool)
{
   $response = '';
   foreach ($_POST as $key => $value) {
       if ($bool == 0) {
           if ($key == "responseCode") {
               $response .= '<tr><td width="50%" align="center" valign="middle">' . $key . '</td>
                   <td width="50%" align="center" valign="middle"><font color=Red>***</font></td></tr>';
           } else if ($key == "responseDescription") {
               $response .= '<tr><td width="50%" align="center" valign="middle">' . $key . '</td>
                   <td width="50%" align="center" valign="middle"><font color=Red>This response is compromised.</font></td></tr>';
           } else {
               $response .= '<tr><td width="50%" align="center" valign="middle">' . $key . '</td>
                   <td width="50%" align="center" valign="middle">' . $value . '</td></tr>';
           }
       } else {
           $response .= '<tr><td width="50%" align="center" valign="middle">' . $key . '</td>
               <td width="50%" align="center" valign="middle">' . $value . '</td></tr>';
       }
   }
   $response .= '<tr><td width="50%" align="center" valign="middle">Checksum Verified?</td>';
   if ($bool == 1) {
       $response .= '<td width="50%" align="center" valign="middle">Yes</td></tr>';
   }
   else {
       $response .= '<td width="50%" align="center" valign="middle"><font color=Red>No</font></td></tr>';
   }

   return $response;
}

public function error_codes()
{
 $transaction_errors =  array('100' => 'The transaction was completeted successfully.',
       '101' => 'Merchant not found. Please check your merchantIdentifier field.',
       '102' => 'Customer cancelled transaction.',
       '103' => 'Fraud Detected.',
       '104' => 'Customer Not Found.',
       '105' => 'Transaction details not matched.',
       '106' => 'IpAddress BlackListed.',
       '107' => 'Transaction Amount Limit Not Matched.',
       '108' => 'Validation Successful.',
       '109' => 'Validation Failed.',
       '110' => 'MerchantIdentifier field missing or blank.',
       '111' => 'MerchantIdentifier Not Valid.',
       '129' => 'OrderId field missing or blank.',
       '130' => 'OrderId received with request was not Valid.',
       '110' => 'Order Id Already Processed with this Merchant.',
       '131' => 'ReturnUrl field missing or blank.',
       '132' => 'ReturnUrl received with request was not Valid',
       '133' => 'BuyerEmail field missing or blank.',
       '189' => 'ReturnUrl does not match the registered domain.',
       '134' => 'BuyerEmail received with request was not Valid.',
       '135' => 'BuyerFirstName field missing or blank.',
       '136' => 'BuyerFirstName received with request was not Valid.',
       '137' => 'BuyerLastName field missing or blank.',
       '138' => 'BuyerLastName received with request was not Valid.', '139' => 'BuyerAddress field missing or blank.',
       '140' => 'BuyerAddress received with request was notValid.',
       '141' => 'BuyerCity field missing or blank.',
       '142' => 'BuyerCity received with request was not Valid.',
       '143' => 'BuyerState field missing or blank.',
       '144' => 'BuyerState received with request was not Valid.',
       '145' => 'BuyerCountry field missing or blank.',
       '146' => 'BuyerCountry received with request was not Valid.',
       '147' => 'Buyer PinCode field missing or blank.',
       '148' => 'BuyerPinCode received with request was not Valid.',
       '149' => 'BuyerPhoneNumber field missing or blank.',
       '150' => 'BuyerPhoneNumber received with request was not Valid.',
       '151' => 'TxnType field missing or blank.',
       '152' => 'TxnType received with request was not Valid.',
       '153' => 'ZpPayOption field missing or blank.',
       '154' => 'ZpPayOption received with request was not Valid.',
       '155' => 'Mode field missing or blank.',
       '156' => 'Mode received with request was not Valid.',
       '157' => 'Currency field missing or blank.',
       '158' => 'Currency received with request was not Valid.',
       '159' => 'Amout field missing or blank.',
       '160' => 'Amount received with request was not Valid.',
       '161' => 'BuyerIpAddressfield missing or blank.',
       '162' => 'BuyerIpAddress  received with request was not Valid.',
       '163' => 'Purposefield missing or blank.',
       '164' => 'Purpose received with request was not Valid.',
       '165' => 'ProductDescription field missing or blank.',
       '166' => 'ProductDescription received with request was not Valid.',
       '167' => 'Product1Description received with request was not Valid.',
       '168' => 'Product2Description received with request was not Valid.',
       '169' => 'Product3Description received with request was not Valid.',
       '170' => 'Product4Description received with request was not Valid.',
       '171' => 'ShipToAddress received with request was not Valid.',
       '172' => 'ShipToCity received with request was not Valid.',
       '173' => 'ShipToState received with request was not Valid.',
       '174' => 'ShipToCountry received with request was not Valid.',
       '175' => 'ShipToPincode received with request was not Valid.',
       '176' => 'ShipToPhoneNumber received with request was not Valid.',
       '177' => 'ShipToFirstname received with request was not Valid.',
       '178' => 'ShipToLastname received with request was not Valid.',
       '179' => 'Date is blank or Date received with request was not valid.',
       '180' => 'checksum received with request is not equal to what we calculated.',
       '181' => 'Merchant Data Complete.',
       '182' => 'Merchant Data Not Complete in Our Database.',
       '183' => 'Unfortunately, the transaction failed due to some unexpected reason in our system.',
       '400' => 'The transaction was declined by the issuing bank.',
       '401' => 'The transaction was rejected by the acquiring bank.');
}

Purchases Controller :

class PurchasesController extends AppController {

public  $components = array('Payments.ZaakPay');

public function beforeFilter()
{
   parent::beforeFilter();
   //$this->Auth->allow('*');
}

public function zaakpay(){

   $orderId = $this->ZaakPay->getOrderId();

   $ZaakMerchantIdentifier = $this->ZaakPay->config['ZaakMerchantIdentifier'];
   $this->set(compact('orderId','item','ZaakMerchantIdentifier'));
}

public function zaakpay_post_data(){

   if(!empty($_POST)){

       $all = $this->ZaakPay->getAllParams();

       $checksum = $this->ZaakPay->calculateChecksum($all);

       $formHtml = $this->ZaakPay->outputForm($checksum);

//create an order & save it to DB if needed

//your code goes here

$this->set(compact('formHtml'));
   }
}

public function zaakpay_response(){

   $original_response = $_POST;

   $recd_checksum = $_POST['checksum'];
   $all = $this->ZaakPay->getAllParams();

   $checksum_check = $this->ZaakPay->verifyChecksum($recd_checksum, $all);
   $response = $this->ZaakPay->outputResponse($checksum_check);

   //update transaction
   if($_POST['responseCode'] == '100'){
        //update your saved order
   }else{
       //delete order
   }

   $this->set(compact('response', 'original_response'));
}

public function zaakpay_updates(){

}

public function zaakpay_check_transaction(){

}

Views for the actions :

For action zaakpay:

<div class=”hero-unit”> <h2>Payment Process </h2>

<form action="/payments/purchases/zaakpay_post_data" method="post">
   <input type="hidden" name="merchantIdentifier" value="<?php echo $ZaakMerchantIdentifier;?>"/>
   <input type="hidden" name="orderId" value="<?php echo $orderId;?>"/>
   <input type="hidden" name="txnType" value="1"/>
   <input type="hidden" name="zpPayOption" value="1"/>
   <input type="hidden" name="mode" value="1"/>
   <input type="hidden" name="currency" value="INR"/>
   <input type="hidden" name="amount" value="item price"/>
   <input type="hidden" name="merchantIpAddress" value="<?php echo $_SERVER['SERVER_ADDR']?>"/>
   <input type="hidden" name="purpose" value="1"/>
   <input type="hidden" name="productDescription" value="product description"/>
   <input type="hidden" name="txnDate" id="txnDate" value="<?php echo date('Y-m-d');?>"/>
           <h2>Pay Now via Zaakpay.</h2>

   <table width="650px;">
       <tr>
           <td colspan="2"> </td>
       </tr>
       <tr>
           <td width="50%" align="right" valign="middle">Song Name</td>
           <td width="50%" align="center" valign="middle"><?php echo $song['Song']['name'];?></td>
       </tr>
       <tr>
           <td width="50%" align="right" valign="middle">Price</td>
           <td width="50%" align="center" valign="middle"><?php echo $song['Song']['price'];?> Rs</td>
       </tr>
       <tr>
           <td colspan="2"> </td>
       </tr>
       <tr>
           <td width="50%" align="right" valign="middle">Buyer Email</td>
           <td width="50%" align="center" valign="middle"><input type="text" name="buyerEmail"
                                                                 value="buyer_email"/></td>
       </tr>
       <tr>
           <td width="50%" align="right" valign="middle">Buyer First Name</td>
           <td width="50%" align="center" valign="middle"><input type="text" name="buyerFirstName"
                                                                 value=""/></td>
       </tr>
       <tr>
           <td width="50%" align="right" valign="middle">Buyer Last Name</td>
           <td width="50%" align="center" valign="middle"><input type="text" name="buyerLastName"
                                                                 value="/></td>
       </tr>
       <tr>
           <td width="50%" align="right" valign="middle">Buyer Address</td>
           <td width="50%" align="center" valign="middle"><input type="text" name="buyerAddress" value=""/></td>
       </tr>
       <tr>
           <td width="50%" align="right" valign="middle">Buyer City</td>
           <td width="50%" align="center" valign="middle"><input type="text" name="buyerCity" value=""/></td>
       </tr>
       <tr>
           <td width="50%" align="right" valign="middle">Buyer State</td>
           <td width="50%" align="center" valign="middle"><input type="text" name="buyerState" value=""/></td>
       </tr>
       <tr>
           <td width="50%" align="right" valign="middle">Buyer Country</td>
           <td width="50%" align="center" valign="middle"><input type="text" name="buyerCountry" value=""/></td>
       </tr>
       <tr>
           <td width="50%" align="right" valign="middle">Buyer Pincode</td>
           <td width="50%" align="center" valign="middle"><input type="text" name="buyerPincode" value=""/></td>
       </tr>
       <tr>
           <td width="50%" align="right" valign="middle">Buyer Phone No</td>
           <td width="50%" align="center" valign="middle"><input type="text" name="buyerPhoneNumber" value=""/>
           </td>
       </tr>
       <tr>
           <td width="50%" align="right" valign="middle"> </td>
           <td width="50%" align="center" valign="middle">
               <input type="submit" name="submit" value="Pay Now"/>
           </td>
       </tr>


   </table>

</form>

</div> Post data for request creation : Above action get submitted to the Purchases controller & then zaak pay component creates a request format & post the data inside form to the payment gateway.

Action : zaak_pay_post_data()

<div class=”hero-unit”> <h2>Payment Process </h2>

<div>
   <h3>Please wait we are redirecting you to the payment gateway.....</h3>
</div>

<form action="https://api.zaakpay.com/transact" method="post" id="paymentForm">
   <?php
   echo $formHtml;
   ?>
</form>

</div>

<script type=”text/javascript”> $(document).ready(function () { $(“#paymentForm”).submit(); });</script>

Now User get redirected to the zaakpay site for payment, user completes the payment & then get returned to the action that is set inside the zaakpay control panel.

Action : zaakpay_response()

<div class=”hero-unit”> <h2><?php echo __(‘Song’); ?></h2> <table cellpadding=”0” cellspacing=”0” width=”100%” class=”table table- condensed”>

<?php
   if ($original_response['responseCode'] == '100') {
       ?>
       <tr>
           <td>
               Your transaction for Order Id <?php echo $original_response['orderId'];?> has been successfully
               completed.
           </td>
       </tr>
       <?php
   } else {
       echo $response;
   }

   ?>
</table>

</div>

This is the flow of successful transaction. We are yet to handle the errors & display them to the page. This is a basic integration, you can modify this as per your need.

Suggestions are welcome. Please contact me on kvijay@weboniselab.com

published on May 20, 2012 12:00 AM

Read more

Download Now - GitHub

Combinator Plugin: Combine, minify and cache CSS and JS files in CakePHP 2.1 ===========

Easily combine, minify and cache Javascript and CSS files for faster load times.

Download Now - GitHub

https://github.com/joshuapaling/CakePHP-Combinator-Plugin

More Info...

This plugin is based on the Cake 1.3 Combinator Article from the Bakery - http://bakery.cakephp.org/articles/st3ph/2010/09/10 /combinator-compress-and-combine-your-js-and-css-files I’ve just made it compatible with CakePHP 2.1, and packaged it as a plugin, including CSSTidy and jsmin.

The plugin is quick and easy to install, and is available (along with documentation) on GitHub: https://github.com/joshuapaling/CakePHP-Combinator-Plugin

PLEASE NOTE - this is my first CakePHP plugin, and also my first public GitHub project. As far as I know the code included is all legit and open source. Please let me know if not.

published on May 19, 2012 12:00 AM

Read more

Extending HttpSocket for use with Amazon among other things for 1.3.x and 2.x

Extending HttpSocket for use with Amazon among other things for 1.3.x and 2.x

When trying to use the Amazon API, I read a lot about the Amazon rule of only being allowed to make 1 request a second or your web site would be refused access to Amazon if this was ignored too often. So I set about solving the issue using CakePHP and ended up with a few classes that could be of use to others. The source for this article is downloadable from Github. The Master branch is for CakePHP1.3.x and there is now a 2.x branch.

The obvious solution to the Amazon request frequency problem is to ensure your website makes no more than 1 request a second. I decided to implement this with a locked file approach that would marshall the requests being made.

The system presented here consists of 3 classes and an interface.

The interface ISocket simply outlines methods as implemented by HttpSocket in CakePHP.

interface ISocket {
    public function put($uri = null, $data = array(), $request = array());
    public function delete($uri = null, $data = array(), $request = array());
    public function get($uri=NULL, $query = array(), $request = array());
    public function post($uri = null, $data = array(), $request = array());
}

The abstract class BaseSocket wraps any ISocket implementing class and takes care of passing calls to that class.

abstract class BaseSocket implements ISocket {
    private $_socket;

    public function  __construct( ISocket $socket ) {
        $this->_socket = $socket;
    }

    public function  delete($uri = null, $data = array(), $request = array()) {
        return $this->_socket->delete($uri,$data,$request);
    }

    public function post($uri = null, $data = array(), $request = array()) {
        return $this->_socket->post($uri,$data,$request);
    }

    public function get($uri = NULL, $query = array(), $request = array()) {
        return $this->_socket->get($uri,$query,$request);
    }

    public function put($uri = null, $data = array(), $request = array()) {
        return $this->_socket->put($uri,$data,$request);
    }
}

The class NormalSocket simply extends HttpSocket and implements ISocket which enables it to be used by BaseSocket. Other than this, it is identical to HttpSocket supplied by CakePHP.

class NormalSocket extends HttpSocket implements ISocket {
    public function __construct($config = array() ) {
        parent::__construct($config);
    }
}

You could use NormalSocket just as you would use HttpSocket.

/* Create a NormalSocket which has the same usage as HttpSocket */
$ns = new NormalSocket();
/* Get content from a URI */
$response = $ns->get($uri);

ThrottledSocket throttles another ISocket implementing object which is passed in the constructor.

class ThrottledSocket extends BaseSocket implements ISocket {

    /**
     * Filename used for synchronisation
     */
    private $_filename;

    /**
     * Create a Throttled Socket.
     */
    public function __construct(ISocket $socket) {
        parent::__construct($socket);
        $this->_filename = ROOT . DIRECTORY_SEPARATOR . APP_DIR . DIRECTORY_SEPARATOR . 'tmp' . DIRECTORY_SEPARATOR . 'throttle.dat';
        if (!file_exists($this->_filename)) {
            file_put_contents($this->_filename, time());
        }
    }

    /**
     * Issues a GET request to the specified URI, query, and request.
     */
    public function get($uri=NULL, $query = array(), $request = array()) {
        $delay = $this->throttle();
        if ($delay > 0) {
            sleep($delay);
        }
        return parent::get($uri, $query, $request);
    }

    /**
     * Issues a POST request to the specified URI, query, and request.
     */
    public function post($uri = null, $data = array(), $request = array()) {
        $delay = $this->throttle();
        if ($delay > 0) {
            sleep($delay);
        }
        return parent::post($uri, $query, $request);
    }

    /**
     * Introduce a delay. Requests are only allowed to be sent
     * once a second.
     */
    private function throttle() {
        $curtime = time();
        $filetime = $curtime;
        $fp = fopen($this->_filename, "r+");
        if (flock($fp, LOCK_EX)) {
            $nbr = fread($fp, filesize($this->_filename));
            $filetime = intval(trim($nbr));
            $curtime = time();
            if ($curtime > $filetime) {
                $filetime = $curtime;
            } else {
                $filetime++;
            }
            rewind($fp);
            ftruncate($fp, 0);
            fprintf($fp, "%d", $filetime);
            flock($fp, LOCK_UN);
        }
        fclose($fp);
        return $filetime - $curtime;
    }
}

You use ThrottledSocket as follows...

$ts = new ThrottledSocket(new NormalSocket());
/* Requests to Throttled socket now happen only once per second */
$response = $ts->get($uri);

CachedSocket caches another ISocket implementing object which is passed in the constructor. The class uses the standard CakePHP Cacheing mechanism to cache the responses returned by the wrapped socket.

class CachedSocket extends BaseSocket implements ISocket {

    /**
     * The cache key
     */
    private $_cacheKey;

    /**
     * The duration of the cache in seconds
     */
    private $_cacheDuration;


    /**
     * Create the object and assign a cache key.
     */
    public function __construct(ISocket $socket, $key, $duration=3600) {
        parent::__construct($socket);
        $this->_cacheKey = $key;
        $this->_cacheDuration = $duration;
    }

    /**
     * Set the number of seconds for which responses should be cached.
     */
    public function setCacheDuration($duration) {
        $this->_cacheDuration = $duration;
    }

    /**
     * Set the cache key
     */
    public function setCacheKey($key) {
        $this->_cacheKey = $key;
    }

    /**
     * GET Request a URL.
     */
    public function get($uri=NULL, $query = array(), $request = array()) {
        $response = Cache::read($this->_cacheKey);
        if ($response === false) {
            $response = parent::get($uri, $query, $request);
            if ($response) {
                Cache::set(array('duration' => '+' . $this->_cacheDuration . ' seconds'));
                Cache::write($this->_cacheKey, $response);
            }
        }
        return $response;
    }

    /**
     * POST Request a URL.
     */
    public function post($uri=NULL, $query = array(), $request = array()) {
        $response = Cache::read($this->_cacheKey);
        if ($response === false) {
            $response = parent::post($uri, $query, $request);
            if ($response) {
                Cache::set(array('duration' => '+' . $this->_cacheDuration . ' seconds'));
                Cache::write($this->_cacheKey, $response);
            }
        }
        return $response;
    }

}

You could use CachedSocket to cache responses from an HttpSocket

/* Cache the NormalSocket with the key 'CacheKey' for 1 hour */
$cs = new CachedSocket(new NormalSocket(), 'CacheKey', 3600 );
/* Requests to Cached socket now return the cached response for the next hour */
$response = $cs->get($uri);

Using this system of wrapping other ISocket implementing objects we can cache throttled requests which is ideal for accessing Amazon. Once a request is made, the response will be cached so amazon requests are only made when necessary and they will not occur more than once per second.

function GetBookByAsin( $asin ) {
    /* Throttle an HttpSocket to send requests at once a second */
    $ts = new ThrottledSocket( new NormalSocket() );
    /* Cache the throttled socket */
    $amazonSocket = new CachedSocket( $ts, 'ASIN' . $asin, 3600 );
    /* Build amazon request URL in $url */
    $response = $amazonSocket->get($url);
    /* Process XML returned by Amazon or by the Cache */
}

The first time the example function is called it will make a throttled request to amazon and cache the response. For the next hour any requests for the same item will return the cached response and not make any calls to amazon at all.

The source code is available from GitHub at the URL shown above and it is simply a matter of copying the classes into your app/libs (or app/Lib for 2.x) directory and using them. I have documented each class and provided a couple of test cases.

Another bonus of wrapping the socket classes in other classes can be seen in the test cases. It is simple to create a dummy class that implements ISocket and feed that to CachedSocket or ThrottledSocket so those classes can be tested without the need of making any actual requests.

published on May 18, 2012 12:00 AM

Read more

Amazon Product Advertising Services Component

Amazon Product Advertising Services Component

A CakePHP 2.x component for using the Amazon PAS The source for this component is available from Github

I first toyed with the idea of making the official AWS/PAS libraries ( available from github in the repositories ‘aws-sdk-for-php’ and ‘cloudfusion’ ) usable by CakePHP but then went away from this as it ties you into using CURL. Personally I would rather have the choice of using Cake’s own HttpSocket to make requests if I choose to or even my own Caching and Throttled versions of HttpSocket.

So instead, I created a component whose sole purpose is to construct URL’s that can then be sent to Amazon using any method I choose in order obtain the information.

Installation, Configuration and Usage documentation are contained within the readme file and the component source so there is little need to repeat it here.

I hope it is of use to someone other than myself !!!

published on May 18, 2012 12:00 AM

Read more

CakeFest 2012

CakeFest 2012

CakeFest 2012 will be in Manchester, UK. With the huge success of last year, combined with the low cost accommodation and great location for travellers, we couldn’t pass up bringing it to Manchester for another year!

CakeFest is the annual CakePHP Conference. It brings together developers, users, and interested parties from all over the world for a four day event filled with workshops, talks, dinners, social events and plenty of fun!

If you are interested in giving a talk at CakeFest, we still have submissions open! Just head over to the CakeFest, sign up and submit your talk proposal via your account page! We’re open to anyone for submissions, and we’d love to hear your ideas!

Tickets are on sale now! Head over to the CakeFest website for ticketing information.

Do you work for or own a business that would benefit from the unique exposure that comes from being a CakeFest Conference Sponsor? We’re currently seeking sponsors for CakeFest 2012, to help us realise a great event and continue the tradition of the awesome CakeFest conference experience. We need the help of the community to spread awareness of the event, and seek out sponsors to support our annual conference. Please email sponsors@cakefest.org for more details.

CakeFest is organised into two sections; the first two days are for workshops, in which CakePHP core contributors conduct lesson style courses where attendees learn about CakePHP at either a beginner or intermediate to advanced level. This selective in-person training is a great way to learn CakePHP, refresh your skills, or to learn new techniques and advanced approaches to boost your development. Taking training at CakeFest is a unique experience, and attendees are rewarded with a certificate issued by the Cake Software Foundation upon completion.

The second part of CakeFest is the conference. This is comprised of a series of talks given by the core developers, community members, and mixed in with lightning talks which enable anyone attending to jump up and talk about a topic! We also conduct a Core Panel discussion, in which you can talk directly to the core developers, and we challenge their knowledge in a public arena!

In amongst all the days of serious (fun) learning, we have social events organised to keep you busy and to provide a great way to network with fellow developers and make new friends!

Check out the CakeFest website, and don’t miss out on tickets!

published on May 8, 2012 12:00 AM

Read more

CakePHP 2.1.2 & 2.2.0-beta released

CakePHP 2.1.2 & 2.2.0-beta released

The CakePHP core team is proud to announce the immediate availability of both CakePHP 2.1.2 [1], and 2.2.0-beta [2]. 2.1.2 is a bugfix release for the 2.1.x branch, while 2.2.0-beta is the first release for 2.2.x.

The CakePHP core team is proud to announce the immediate availability of both CakePHP 2.1.2 [1], and 2.2.0-beta [2]. 2.1.2 is a bugfix release for the 2.1.x branch, while 2.2.0-beta is the first release for 2.2.x.

CakePHP 2.1.2

There are a number of bugfixes in 2.1.2, the most notable of those changes is:

  • Set::insert() now overwrites values that were previously string values.
  • AuthComponent now uses loginRedirect as the default redirect location, should the session be empty.
  • CakeNumber::format() now supports multiple bytes for thousands/decimals when using PHP lower than PHP 5.4
  • A change to CakeSession was reverted to help solve issues with IE8 and sessions being lost.
  • Fixed an issue with SQLServer + boolean columns.
  • DboSource::buildJoinStatement() does not add the schema when the table is a subquery.
  • SessionComponent::id() always returns the sessionid. It will auto- start the session if necessary.
  • Method checking in Model for expression() and calculate() is only done when required now.
  • The testsuite now always uses the test datasource. Previously, if you did not include any fixtures and ran tests that required the database, the default connection was used.
  • URL fragments are no longer urlencoded. This caused issues with client side frameworks like backbone.
  • The return of L10n::get() consistently returns the language.
  • HTML escaping for string urls on css() and script() was fixed.
  • Warnings from saveAll() with an empty hasMany data set are fixed.
  • Validation::decimal() accepts values like 10 and 10.0 .
  • FormHelper::postButton() no longer makes invisible buttons.
  • The $_FILES array is now recursively reformatted. This fixes issues when file inputs are deeply nested.
  • EmailComponent no longer double encodes addresses containing UTF-8 characters.
  • File::create() no longer juggles umask. This was a workaround for file caching which is no longer needed.

CakePHP 2.2.0-beta

Following hot on the heels of 2.1.0, the CakePHP team is proud to announce the beta release for 2.2.0. 2.2.x will be an API compatible release with 2.0.x, and 2.1.x. All of the changes mentioned in the 2.1.2 release, are also be present in 2.2.0-beta. We’ve decided to skip the standard ` -dev` and ` -alpha` releases, as we think the new features are relatively stable, and should be generally transparent when upgrading. A quick list of new features added in 2.2.0-beta:

Timezone support for CakeTime utility

  • Added “Config.timezone” param to configure global timezone for the application.
  • CakeTime functions can now use timezone string or DateTimeZone object for user offsets
  • The $userOffset parameter has been replaced with $timezone parameter in all relevant functions.
  • Passing numeric offsets for $timezone parameter is still possible for backwards compatibility.
  • New methods added: CakeTime::toServer() and CakeTime::timezone()`

Support pagination for complex custom finders

Model ` findCount()` will now pass ` $query[‘operation’]=’count’` for more flexibility.

In many cases custom finds already return correct counts for pagination, but ‘operation’ key allows more flexibility to build other queries, or drop joins which are required for the custom finder itself. As the pagination of custom find methods never worked quite well it required workarounds for this in the model level, which are now no longer needed

ACL methods now part of Permission model

Now the Permission model has available all methods exposed in the AclComponent for easier permissions check in the model layer.

New Hash class

A new utility library ` Hash` was added. It is intended as a replacement for the Set class featuring improved performance, and a more consistent API. All internal calls to Set were replaced and Set has been deprecated and will be removed in the next major version.

Also added were Set::expand() and Hash::expand() to convert a plain list of dot separated keys into a nested array.

Helper Lazy Loading

Helpers located in the app folder can now be lazy loaded, there is no need to declare helpers anymore in the ` $helpers` controller property if they are located in the app folder and you do not rely on them triggering any callback.

Redis cache engine

A new cache engine was added to interface with a Redis server, which is similar to Memcache

Cache groups

It is now possible to tag or label cache keys under groups. This makes it simpler to mass-delete cache entries associated to the same label. Groups are declared at configuration time when creating the cache engine

Fatal error & console error handlers

You can now configure separate error handlers for console and fatal errors. If you leave these configurations undefined the defaults will be used. If you are using a custom error handler, it will now receive fatal error codes, in addition to the other types.

Nested transaction support

Dbo datasources now supports real nested transactions. If you need to use this feature in your application, enable it using ` ConnectionMana ger::getDataSource(‘default’)->useNestedTransactions=true;`

Dispatcher filters

Event listeners can now be attached to the dispatcher calls, those will have the ability to change the request information or the response before it is sent to the client. ` app/Config/bootstrap.php` should be changed to add configuration related to Dispatcher filters. If your application relies on assets in themes or plugins being dispatched, or if your are using the full page caching feature you must copy the relevant configuration to your bootstrap file. You need to add the following:

<?php
Configure::write('Dispatcher.filters', array(
    'AssetDispatcher',
    'CacheDispatcher'
));

Additionally, the new AssetDispatcher filter will return a 304 code if it can detect the browser has the asset cached already

Other Changes

  • Add charset() / headerCharset() methods to CakeEmail class
  • Travis CI support
  • Added support for ‘on’ validation key in FormHelper. This will set the required class accordingly depending on the type of operation (create or update)

Following the beta of 2.2.0, the core team will be focusing on solidifying 2.2.x towards a final release, and beginning inital work on the next release of CakePHP.

As always, thanks to the friendly CakePHP community for the patches, documentation changes and new tickets. Without you there would be no CakePHP!

published on Apr 30, 2012 12:00 AM

Read more

AWS SES component for CakePHP2.0 +

AWS SES component for CakePHP2.0 +

This is an Amazon SES component. Developed to help developers to move & integrate faster the AWS services. In future we will come up with the aws plugin with all the services

We use Amazon services for our day today applications & we use their SDK & write normal code to required controllers, So we planned to create a component for AWS service.

Amazon Simple Email Service (Amazon SES) is a very popular email SMTP service by Amazon. It has lots of advantages like,

Easy to use
Good documentation
Good fault tolerance
Easy to integrate with existing architecture
Detailed reporting about email deliveries
Highly scalable

Once you go with AWS services, it is advised to use their services throughout your application. like EC2 for hosting your application, SES for sending email via authenticated & trusted SMTP server. You can use AWS SES service alone also.

So for using Amazon Simple Email Service (Amazon SES) service use following steps, 1. You need an AWS account. http://aws.amazon.com/ 2. Login to the account & go to the SES dashboard. 3. Add email address to verify. Which can be used in From header of outgoing emails. 4. After adding email, AWS sends an verification email to the email address. You need to verify this email address. Then it will appear in the verified email list.

http://docs.amazonwebservices.com/ses/latest/DeveloperGuide/InitialSetup.EmailVerification.html

By default in the 1st go AWS gives you a sandbox testing account. In this mode it will only send emails to & from the verified email addresses only.

For using SES with your application you need production access. So first up all request to activate the production mode. It will take one business day to activate. After this activation you can send emails through your application.

Now there is a Verified email address section in the SES dashboard. These email addresses you can use in the From header of your outgoing email. If the email address is not verified you can not use that email address.

Now the Implementation part comes in the picture with CakePHP app. It’s very easy to integrate SES with the application.

Download the SDK (PHP) from AWS. http://aws.amazon.com/code
Extract the sdk to your ‘app/Vendor’ directory.
Rename it as ‘aws’ from ‘aws-sdk’
Create a component file in the components directory. name : AWSSESComponent.php
Copy paste the code to this file
Add the line to Appcontroller :

include_once(APP.DS.’Vendor’.DS.’aws/sdk.class.php’); or App::import(‘Vendor’, ‘aws/sdk.class’);

Add ‘AWSSES’ in the public $components = array('AWSSES');
Now you can use this in any controller. If you want to use this controller specific then in every controller you can add the component array.

Currently this component only supports the HTML email formats, but we are going to improve this further. This is the inspiration from Swiftmailer component & SES:

<?php App::import('Vendor', 'aws/sdk.class.php');
App::import('Vendor', 'aws/services/ses.class.php');

class AWSSESComponent extends Object {

    public $ses;
    public $emailViewPath = '/Emails';
    public $emailLayouts = 'Emails';
    public $htmlMessage;
    public $from = 'from_email_address';
    public $to;

    public function initialize($controller)
    {

    }


    function startup(&$controller)
    {
       $this->controller =& $controller;

       $this->ses = new AmazonSES(array('certificate_authority' => false,
           'key' => 'AWS_Key',
           'secret' => 'AWS_secrete'));

    }

    public function beforeRender()
    {
    }

    public function shutdown()
    {
    }

    public function beforeRedirect()
    {
    }

    public function _aws_ses($viewTemplate, $mailContent = null)
    {
           if(!empty($this->controller->request->data) && $mailContent == null){
           $mailContent = $this->controller->request->data[$this->controller->modelClass];
       }

       $mail = $this->email_templates($viewTemplate);

       $destination = array(
           'ToAddresses' => explode(',', $this->to)
       );
       $message = array(
           'Subject' => array(
               'Data' => $mail['Subject']
           ),
           'Body' => array()
       );


       $this->controller->set('data', $mailContent);

       $this->htmlMessage = $this->_getHTMLBodyFromEmailViews($mail['ctp']);

       if ($this->htmlMessage != NULL) {
           $message['Body']['Html'] = array(
               'Data' => $this->htmlMessage
           );
       }

       $response = $this->ses->send_email($this->from, $destination, $message);

       $ok = $response->isOK();

       if (!$ok) {
           $this->log('Error sending email from AWS SES: ' . $response->body->asXML(), 'debug');
       }
       return $ok;
    }

    public function email_templates($name)
    {
       $this->templates = array('email_name' => array(
           'ctp' => 'ctp_file_name', 'Subject' => 'email_subject'
       ),'email_name' => array('ctp' => 'reset_passwordctp_file_name 'Subject' => 'email_subject'));

       return $this->templates[$name];
    }

    public function _getHTMLBodyFromEmailViews($view)
    {
       $currentLayout = $this->controller->layout;
       $currentAction = $this->controller->action;
       $currentView = $this->controller->view;
       $currentOutput = $this->controller->output;

       ob_start();
       $this->controller->output = null;

       $viewPath = $this->emailViewPath . DS . 'html' . DS . $view;
       $layoutPath = $this->emailLayouts . DS . 'html' . DS . 'default';

       $bodyHtml = $this->controller->render($viewPath, $layoutPath);

       ob_end_clean();

       $this->controller->layout = $currentLayout;
       $this->controller->action = $currentAction;
       $this->controller->view = $currentView;
       $this->controller->output = $currentOutput;

       return $bodyHtml;
    }

}

So CakePHP 2.0 + uses an Email views to store all the email templates. You can change the location & you can use your own too.

Template views from View/Emails/html/email.ctp’ as defined in the component : $emailViewPath Layouts from your ‘View/Layouts/Emails/default.ctp’ as defined in the component : $emailLayouts

This component catches the post data itself & you can use that data in your emails. If you don’t want to capture the data from post request & you want to set your data that is also possible, only add the second param as array & you can get that in your email view as ‘$data’ array.

How to use n controller :<?php //email to //you can send comma separated email addresses if you want to send email to multiple people.

$this->AWSSES->to = $this->request->data[‘User’][‘username’];

if ($this->AWSSES->_aws_ses(‘email tempate name’, ‘optional param’)) { //optional param : can be an array of the data that you want to access in email view.

//your code } ?>

published on Apr 24, 2012 12:00 AM

Read more

GoogleChart helper

GoogleChart helper

GoogleChart is a helper class for easy generating image charts using Google Chart API.

I needed simple access to Google Chart API for generating images. Please see examples below and method comments in source file to see how it works.

This plugin is for CakePHP 2.x

Example: ` //Controller: public$helpers=array(‘GoogleChart.GoogleChart’); `

` //View: //exampleofbarchart echo$this->GoogleChart->create() ->setType(‘bar’,array(‘horizontal’,’grouped’)) ->setSize(500,400) ->setMargins(5,5,5,5) ->addData(array(1200.48,432.3,647.21,635.2)) ->addMarker(‘value’,array(‘format’=>’f1’,’placement’=>’c’)) ->addData(array(20,42.3,65.21,95.2)) ->addMarker(‘value’,array(‘size’=>14,’color’=>‘000000’)) ->addAxis(‘x’,array(‘labels’=>array(‘jan2012’,’feb2012’))) ->addAxis(‘y’,array(‘axis_or_tick’=>’l’,’size’=>12));

//exampleofpiechart echo$this->GoogleChart->create() ->setTitle(‘CHARTTITLE’,array(‘size’=>14,’color’=>‘000000’)) ->setType(‘pie’,array(‘3d’)) ->setSize(600,300) ->setMargins(10,10,10,10) ->addData(array(20,35,50,10)) ->setPieChartLabels(array(‘first’,’second’,’third’,’andsoon...’)); ` Download the code from https://github.com/segy/GoogleChart

published on Apr 23, 2012 12:00 AM

Read more

Breadcrumbs trail for unordered pages

Breadcrumbs trail for unordered pages

The Idea is to create a trail of visited pages, allowing you to always jump back and to alway see last visited pages. This can be helpful if breadcrumbs can not be used, since there is no clean hierachical structure with parent/child defined. Furthermore, this Component / Helper is only included once for the appController itself and once in your layout. No need to manually add the code to each and every page.

I also played with $referer variable, back button usage and javascript back-functions but in the end the trac was always getting kind of mixed up by functions / methods like save, edit, etc. This Component/Helper pack will allow you to customize methods and controllers to be ignored and to display a nice, clickable trail in the form of

Component ( index ) > Component ( view) > Component2 ( index ) >

This bundle consists of a Component - which may be called from appController itself only once or from each controller by itself - and of a Helper, which is called within your view or in the layout directly. If called from the Layout, make sure to add the Helper to your app_controller as described in step 3 of the Installation how to.

=== Component ===

<?php
/**
 * NavigationComponent
 **
 *
 * @author  Rene Weber
 * @website http://www.webrene.com
 * @modified by Rene Weber, 23.04.2012
 * @version 1.0
 * @cakephp 1.3
 *
 **
 * Purpose
 * ---------
 * Track your way and allow Backwards movement.
 * The Idea is to create a trail of visited pages, allowing you always jump back.
 * This can help if a breadcrumb logical can not be used, since there is no clean hierachical structure
 * with parent/child structure
 * I also played with referer variable, back button usage and javascript back but in the end the trac was
 * always getting messed by functions / methods like save, edit, etc.
 *
 * This Component/Helper pack will allow you to customize methods and controllers to be ignored and to
 * display a nice, linked trail in the form of
 * Component ( index ) > Component ( view) > Component2 ( index ) >
 *
 *
 * What does it constis of
 * -------------------------
 * 1. NavigationComponent ( this file )
 *    The component constists of 4 Functions:
 *    - process: The main function to be called from appController: Stores current page,
 *                                                                                                                                    handles clicks on links,
 *                                                                                                                                    keeps trail short
 *    - storeTrail : Stroes current trail to session ussing $sessionVarName
 *        - walkBack   : If a Link was clicked in our trail, remove all visited pages behind this link
 *                                 This only happens for links passing $navpointUrl and the index.
 *                                     See corresponding NavigationHelper to created correct links
 *    - shrinkTrail: Shift trail until it's length reaches $maxItems or the given length
 *    - cleanTrail: Call this on logout in order to remove trail variable
 *
 * 2. NavigationHelper
 *         Meant to create correct Links to jump back in time. These links also include the index in our trail
 *    and therefor the trail will be adjusted after clicking such a link.
 *
 *
 * Installation
 * ----------------
 *
 * 1. Add Component to app/controllers/components/
 * 2. Add Helper to app/views/helpers/
 * 3. Add Helper to AppController ( nessecary to use in layout) in app/app_controller.php:
 *
 *           var $helpers = array(...       , 'Navigation');
 *             --> If $helpers was not defined yet, you will have to add all used helpers like 'Html' etc.
 *
 * 4. Call 'process' in app_controller.php directly at the beginning of beforeFilter and set variable
 *
 *             $this->Navigation->Process( $this );
 *            $this->set('trail', $this->Navigation->trail );
 *
 * 5. In your Layout or in your desired View, call the trail creator or only read the link:
 *
 *            $this->Navigation->printBacklinks( $trail, 8 )
 *            or
 *            echo $this->Html->link("Back", $this->Navigation->getBacklinkForView( $trail ) );
 *
 * 6. Possibly you want to enclose 'printBacklinks' into a div and adjust its hover and look.
 *    i.e.
 *    <div class='crumb'>$this->Navigation->printBacklinks( $trail, 8 )</div>
 *    and
 *    .crumbs {    color: #999; }
 *        .crumbs a { color: #aaa;    font: 0.9em arial; }
 *    .crumbs a:hover { font-size: 1em; color: #000; font-weight: bold; }
 *
 *
 *
 */

class NavigationComponent extends Object {

    /************************************** GLOBAL VARIABLES MAY BE ADJUSTED ***************************************/


        /**
     * Methods that shall not be stored. I.e. going from Index to View to Edit to Save
     * forwarding you to View again, a back button should ignore the Edit but push you back to Index.
     */

    var $ignoreMethods     = array( 'edit', 'save' );
    var $ignoreControllers = array( 'CakeError', 'Users' );


    /**
     * Keyname to store session variable in
     */

       var $sessionVarName        = 'Navigation';


       /**
        * This is the key we will use in URL to pass the index to our component.
        * Default is 'navpoint' and MUST BE THE SAME IN HELPER!
        * i.e. http://myhost/posts/123?navpoint=3  -> Will jump to 3rd point and delete the rest behind
        */

       var $navpointUrl            = 'navpoint';



       /**
        *  Maximum entries in our trail variable. Default: 8
        */

       var $maxItems = 8;




       /******************************** END OF GLOBAL VARIABLES. DO NOT CHANGE BELOW ***********************************/



       /**
        *  Array holding the Trail we are Moving in
        */

       var $trail = array();




       /**
         * Write Trail to Session
        */

       function storeTrail(){

           $this->Session->write( $this->sessionVarName, $this->trail );

       }


       var $components = array('RequestHandler', 'Session');



       /**
         * If a navigation click brought us here, let's clean all other items
         * This happens if we came here via helper. This can be parsed from the params.
         * e.g. /posts/view/1/navpoint/3  --> Navpoint = 3, clean everything behind
         * It will be next value behind navpoint
        */

       function walkBack( &$controller ){

           if( isset( $controller->params['url'][$this->navpointUrl] ) ){

               for ( $i=sizeof($this->trail); $i>$controller->params['url'][$this->navpointUrl]; $i-- ){
                   unset( $this->trail[$i] );
               }

           }

       }



       function process( &$controller ) {


           $skipThis = 0;

           $controllerName     = $controller->name;


           /* Restore from Session if exists */
           if( ( $sessionVar = $this->Session->read( $this->sessionVarName ) ) )
               $this->trail = $sessionVar;


           /* Check if one of our crumbs was clicked ( will be passed via URL ) */
           $this->walkBack( $controller );


           /* Check if current Method is included in our Ignore List */

           if( in_array( $controller->params['action'], $this->ignoreMethods ) )
               $skipThis = 1;

           /* Check if current Controller is included in our Ignore List */
           if( in_array( $controller->name, $this->ignoreControllers ) )
               $skipThis = 1;


            /* Ignore reload of same controller and same action */

           if( sizeof( $this->trail ) > 0 ){

               $lastElement = $this->trail[sizeof( $this->trail ) -1 ];

               if ( !empty( $lastElement['url'] ) &&
                       $lastElement['url'] == $controller->params['url']['url'] ) {

                           $skipThis = 1;
               }
           }


           /* Add current Page to trail */
           if( $skipThis != 1 )
                $this->trail[] = array(  'url'                 =>    $controller->params['url']['url'],
                                                                    'action'         => $controller->params['action'],
                                                                    'controller' => $controllerName,
                                                            );


           /* Shorten Trail to maximum lenght */
           $this->shrinkTrail();

           /* Store trail to session */
           $this->storeTrail();

       }


        function shrinkTrail( $length=-1 ){

          if( $length == -1 ){
              $length = $this->maxItems;
          }

          while( sizeof( $this->trail ) > $length ){
              array_shift( $this->trail);
          }

      }



       function cleanTrail() {

              $this->trail = array();
               $this->Session->delete( $this->sessionVarName );

       }



}

=== Helper ===

<?php
/**
 * NavigationHelper
 **
 *
 * @author  Rene Weber
 * @website http://www.webrene.com
 * @modified by Rene Weber, 23.04.2012
 * @version 1.0
 * @cakephp 1.3
 *
 **
 *
 * Purpose
 * ---------
 * Create Links for jumping back in trail and add Information for NavigationComponent to adjust its trail
 *
 *
 * Which files are needed?
 * -------------------------
 * 1. NavigationHelper ( This file )
 *         Meant to create correct Links to jump back in time. These links also include the index in our trail
 *    and therefor the trail will be adjusted after clicking such a link.
 *    - printBackLinks:            Need trail variable and length
 *                                                    Will print length amount of the last visited pages with links in one row seperated
 *                                                    by $this->seperator ( see global variables )
 *        - getBacklinkForView:    Yes, this is a long function name. It will return only an URL to be used.
 *
 * 2. NavigationComponent
 *    The component constists of 4 Functions:
 *    - process: The main function to be called from appController: Stores current page,
 *                                                                                                                                    handles clicks on links,
 *                                                                                                                                    keeps trail short
 *    - storeTrail : Stroes current trail to session ussing $sessionVarName
 *        - walkBack   : If a Link was clicked in our trail, remove all visited pages behind this link
 *                                 This only happens for links passing $navpointUrl and the index.
 *                                     See corresponding NavigationHelper to created correct links
 *    - shrinkTrail: Shift trail until it's length reaches $maxItems or the given length
 *
 *
 *
 *
 * Installation
 * ----------------
 *
 * See Component!
 *
 **
 * @author  Rene Weber
 * @website http://www.webrene.com
 * @modified by Rene Weber, 23.04.2012
 * @version 1.0
 * @cakephp 1.3
 *
 */


class NavigationHelper extends AppHelper {



    /************************************** GLOBAL VARIABLES MAY BE ADJUSTED ***************************************/


    /**
     * This array allows you to define aliases for printBackLinks function. Simple example:
     * Without aliases:  Posts ( indexEditor ) > Messages( indexNoNews ) > ...
     * With aliases:         Posts ( Mine )              > Messages( Read )              >...
     */

    var $actionAliases        = array(    'indexSelection'     => 'Type Selection',
                                                                    'indexGrouped'       => 'Grouped',
                                                                    'indexEditor'             => 'My Edits',
                                                                    'index'                        => '',
                                                                    'indexNoNews'            => 'No News',
                                                                    'indexOldVersion' => 'Old Version',
                                                                );

    /**
     * Seperator for function printBackLinks
     */

    var $seperator = "   >   ";


  /**
     * This is the key we will use in URL to pass the index to our component.
     * Default is 'navpoint' and MUST BE THE SAME IN HELPER!
     * i.e. http://myhost/posts/123?navpoint=3  -> Will jump to 3rd point and delete the rest behind
     */

    var $navpointUrl                = 'navpoint';


    /******************************** END OF GLOBAL VARIABLES. DO NOT CHANGE BELOW ***********************************/


    var $helpers                         = array( 'Html' );
    var $controllerAliases     = array();


    function printBackLinks( $trail, $count = 1 ) {


        for ( $i=$count; $i>0; $i-- ){

            if( sizeof( $trail ) < $i )
                continue;

                $lastElement = $trail[sizeof( $trail ) - $i ];

                $displayController     = $lastElement['controller'];
                $displayAction             = $lastElement['action'];

                if( isset( $this->actionAliases[ $lastElement['action'] ] ) )
                    $displayAction         = $this->actionAliases[ $lastElement['action']];

                if( isset( $this->controllerAliases[ $lastElement['controller'] ] ) )
                    $displayController = $this->controllerAliases[ $lastElement['controller'] ];

                if( !empty( $displayAction ) )
                    $displayAction = '( '.$displayAction.' )';

                $url = '/'.$lastElement['url'].'?'.$this->navpointUrl.'='.(sizeof( $trail ) - $i);
                echo $this->Html->Link( $displayController.$displayAction, $url );
                echo $this->seperator;
            }

        }



        function getBacklinkForView( $trail ) {

            $url = '';

            if( isset( $trail[sizeof( $trail ) - 2 ] ) ){
                $lastElement = $trail[sizeof( $trail ) - 2 ];

                $url = '/'.$lastElement['url'].'?'.$this->navpointUrl.'='.(sizeof( $trail ) - 2);
            }

            return $url;


        }






}

?>

published on Apr 23, 2012 12:00 AM

Read more

from Cake to Bake

from Cake to Bake

I will explain how i got CakePHP working from start (Download) to finish (Bake). This tutorial is for PHP/MYSQL on Mint 12/Ubuntu users. I assume that you have installed PHP/MYSQL and apache configured already, you can find many tutorials for doing that, hence i will focus on CakePHP. I also assume that you have created atleast one table in your database by following naming conventions in CakePHP which is pretty easy task :)

  1. Download the latest version of Cake from http://cakephp.org/
  2. Go to your Download folder (or where ever you downloaded your folder), Extract the folder in the same location.
  3. Move the folder to your application root. (In my case /var/www/ )if you face permission denied while copy/paste, use “gksu nautilus” to open the target location.
  4. Rename the folder, MyCake
  5. Use this to change permissions, “sudo chmod -R 777 /var/www/MyCake/”
  6. Delete the folder named “app” from /var/www/MyCake/ , we will be using folder that will be created by bake
  7. So far you have downloaded and set up Cake, now lets install cake bake utility. Run this in your terminal to install cake, ” sudo apt- get install cakephp-scripts ” this will help in baking later. This will also create new folder in “/usr/share/php” named cake

Important: Use sudo gedit /etc/apache2/sites-available/default to edit the contents to follow:

<Directory /var/www/> Options Indexes FollowSymLinks MultiViews AllowOverride All Order allow,deny allow from all </Directory>

  1. Run this in your terminal. This command will create a folder named app in your MyCake folder cake bake -app /var/www/MyCake/app/ This will ask you below:

What is the full path for this app including the app directory name? Example:/var/www/MyCake/app/myapp [/var/www/My-CakePHP/aapp/myapp] >

You must give it path to where you want app folder created, in this case type below:

/var/www/MyCake/app/

This will create new folder named app and new files under it.

  1. Again run the same command, this time we want to use its CRUD functionality called Bake.

after running this command below: cake bake -app /var/www/MyCake/app/

it might tell you that your database.php file cannot be found and that if you want to create the same, tell it yes and provide all the details, do not modify first option ($default), this is a variable that should be left untouched.

or it will ask you what you want to do?

Welcome to CakePHP v1.3.7 Console

App : app Path: /var/www/My-CakePHP/app B0x1A0 Interactive Bake Shell B0x1A0 [D]atabase Configuration [M]odel [V]iew [C]ontroller [P]roject [F]ixture [T]est case [Q]uit What would you like to Bake? (D/M/V/C/P/F/T/Q) >

tell it that you want to create Model by typing M

Bake Model Path: /var/www/My-CakePHP/app/models/ B0x1A0 Use Database Config: (default/database) [default] >

enter “database”

and so on....

Rest is very intutive and help you create controllers and view.

You can then access your site using http://localhost/MyCake/ or if you created controller by the name, posts, use http://localhost/MyCake/posts.

published on Apr 22, 2012 12:00 AM

Read more

Prevent render layout elements with the render of some views!

Prevent render layout elements with the render of some views!

This snippet is meant by the situation in-which you want to prevent some elements in the layout from render while some views is rendered.

Consider the following example, there is an element that displays the top searched keywords and it is named top_searches.ctp. This element is placed in the layout to be rendered under the search box element.

Suppose now, we have an index view that lists all searched keywords and we don’t want to make the top_searches elements to be rendered while we call the index view.

We should add the following code snippet into the most upper line of top_searches, i.e line 1.

<?php
$e = explode('views/elements/',__FILE__);
$e[1] = str_replace('.ctp', '', $e[1]);
if (isset($this->preventElement) && $e[1] == $this->preventElement[$e[1]]) return false;
?>

Simply the above code extracts the path and name of the element’s ctp file relative to the elements directory, then, it asks for an array property of the View object called preventElement, if it find the name of the element is set as a key valued by its name too, it will return false to prevent the rest of the element to be rendered.

Now in the index.ctp we should add the following code:

<?php $this->preventElement['top_searches'] = 'top_searches';?>

I placed the above line of code on the first line too, it is, obviously, that we defined the preventElement property and we set the name of the element we want to stop or prevent its render.

There is a working example of this snippet at:http://quran.2index.net You will see a list for top searched keywords, you will see the last item is red button that linked to the full index of all searched keywords, at this linked page, you will not see the to searched keywords list. Notice: The working example website in Arabic language.

published on Apr 20, 2012 12:00 AM

Read more

Fixing and improving the TextHelper

Fixing and improving the TextHelper

The TextHelper is a really useful utility in CakePHP. But some functions behave strangely and others are missing. That’s why I extended it as follows. General I created a new helper which the following file in “/app/view/helpers/Text2Helper.php”:

<?php
App::import('Helper', 'Text');

class Text2Helper extends TextHelper {
    public function function_name($parameters) {
            // some code

            // if you want to extend functionality, maybe you want
            // to call the parent function
            parent::function_name($parameters);
    }
}
?>

You can overwrite and create new functions in this file. (See: http://ask.cakephp.org/questions/view/how_can_i_extend_the_core_helpers)

Note that you can not use the helper with adding “Text2” to the $helpers array inside a controller. Unfortunately you cannot globally specify to always use the Text2Helper instead of the TextHelper! The only thing you can do is to add the following to your view:

$this->Text = $this->Text2;

I would like to see a functionality to alias helpers! This would make the job easier and prettier. (http://cakebaker.42dh.com/2008/10/18/dont-abuse-the-apphelper-to-extend-the-core-helpers/#comment-110649)

So let’s start with my modifications:

1.) Increasing toList() functionality I added the functionality to specify who each item should be displayed (some sourrounding code and so on). Therefore I added the parameter $phrase. _key_ will be replaced by the current element’s key and _item_ will be replaced by the current element’s value.

<?php
    public function toList($list, $and = 'and', $separator = ', ', $phrase = '_item_') {
            foreach($list as $key => &$item)
                    $item = str_replace(array('_key_', '_item_'), array($key, $item), $phrase);
            return parent::toList($list, $and, $separator);
    }
?>

2.) Fixing truncate() Currently the truncate() function only breaks on spaces. So when you only have newline characters or tabs, the code won’t break. That’s why even very long strings may result in ”...”. Therefore I added 3 fixes.

2.1.) Fixing punctuation Some people don’t add spaces after dots, commas and so on. That’s why I added exactly one space after each of these characters:

<?php
    // 1. fix punctuation
    if ($options['fix_punctuation']) {
            $punctuation = ',.;:';
            $text = preg_replace('/(['.$punctuation.'])[\s]*/', '\1 ', $text);
    }
?>

2.2.) Fixing spaces All possible space symbols (like newline, tab, ...) are replaced by one space character:

<?php
    // 2. fix spaces
    if ($options['fix_spaces']) {
            //$spaces = " \t\r\n";          // use preg_replace() or str_replace() or strtr()
            $text = preg_replace('/[[:space:]]+/', ' ', $text);             // [:space:] equal \s
    }
?>

2.3.) Switch to cut instead of clear When the returned string is still only ‘...’ then set ‘exact’ => true (cutting instead of searching for spaces):

<?php
    // get truncated string
    $result = parent::truncate($text, $length, $options);

    // 3. fix long strings: cut instead of clear
    if ($options['fix_longStr']) {
            if ($result === $options['ending']) {
                    $options['exact'] = true;
                    $result = parent::truncate($text, $length, $options);
            }
    }
?>

So here is the whole code of my truncate function:

<?php
    public function truncate($text, $length = 100, $options = array()) {
            $default = array(
                    'fix_punctuation' => true,
                    'fix_spaces' => true,
                    'fix_longStr' => true, 'ending' => '...'
            );
            $options = array_merge($default, $options);

            // 1. fix punctuation
            if ($options['fix_punctuation']) {
                    $punctuation = ',.;:';
                    $text = preg_replace('/(['.$punctuation.'])[\s]*/', '\1 ', $text);
            }

            // 2. fix spaces
            if ($options['fix_spaces']) {
                    //$spaces = " \t\r\n";          // use preg_replace() or str_replace() or strtr()
                    $text = preg_replace('/[[:space:]]+/', ' ', $text);             // [:space:] equal \s
            }

            // get truncated string
            $result = parent::truncate($text, $length, $options);

            // 3. fix long strings: cut instead of clear
            if ($options['fix_longStr']) {
                    if ($result === $options['ending']) {
                            $options['exact'] = true;
                            $result = parent::truncate($text, $length, $options);
                    }
            }

            // return truncated string
            return $result;
    }
?>

3.) Add wordwrap() This function automatically inserts a newline after a maximum number or characters. Please not that this mostly only useful when you have “text-align: justify;” in your css style. Otherwise it’s often better to set “word-wrap: break-word;” in your css to let the browser do the work. That’s because of the different widths for the different characters for most fonts.

So here is my code:

<?php
/**
 * Splits string in lines of given length.
 * Note: Perhaps it's better to set the following css option: "word-wrap: break-word;"
 *           because it handles the different widths of the characters correctly
 *
 * @param string $text String to wrap.
 * @param integer $length Maximum length (number of characters) of returned lines.
 * @param bool $cut If the cut is set to TRUE, the string is always wrapped at or before the specified width. So only if you have a word that is larger than the given width, it is broken apart.
 * @param bool $htmlBreak Inserts '<br />' on every newline.
 * @return string Wrapped string.
 */
    public function wordwrap($text, $length = 100, $cut = true, $htmlBreak = true) {
            $text = wordwrap($text, $length, "\n", $cut);
            return (($htmlBreak)?nl2br($text):$text);
    }
?>

I hope you find this information useful. When you are of the CakePHP team, consider implementing these fixes into the original TextHelper ;)

published on Apr 20, 2012 12:00 AM

Read more

Prevent render layout elements with the render of some views!

Prevent render layout elements with the render of some views!

This snippet is meant by the situation in-which you want to prevent some elements in the layout from render while some views is rendered.

> ### Updated ###

> In the conditional statement:

>

if (isset($this->preventElement)...

> $this->preventElement becomes $this->preventElement[$e[1]], to solve missing index error generated when using this snippet with more than one element in the layout.

Consider the following example, there is an element that displays the top searched keywords and it is named top_searches.ctp. This element is placed in the layout to be rendered under the search box element.

Suppose now, we have an index view that lists all searched keywords and we don’t want to make the top_searches elements to be rendered while we call the index view.

We should add the following code snippet into the most upper line of top_searches, i.e line 1.

<?php
$e = explode('views/elements/',__FILE__);
$e[1] = str_replace('.ctp', '', $e[1]);
if (isset($this->preventElement[$e[1]]) && $e[1] == $this->preventElement[$e[1]]) return false;
?>

Simply the above code extracts the path and name of the element’s ctp file relative to the elements directory, then, it asks for an array property of the View object called preventElement, if it find the name of the element is set as a key valued by its name too, it will return false to prevent the rest of the element to be rendered.

Now in the index.ctp we should add the following code:

<?php $this->preventElement['top_searches'] = 'top_searches';?>

I placed the above line of code on the first line too, it is, obviously, that we defined the preventElement property and we set the name of the element we want to stop or prevent its render.

published on Apr 19, 2012 12:00 AM

Read more

SELECT FOR UPDATE (hack) (kind of ugly but it works) (PostgreSQL and MySql)

SELECT FOR UPDATE (hack) (kind of ugly but it works) (PostgreSQL and MySql)

Sometimes one needs to do a SELECT ... FOR UPDATE in order to preserve the integrity of our transactions. This isn’t at the moment supported by CakePHP model find operations. Here is a use-at-you-own-discretion ‘hack’, which saves coding time if you are in a hurry (like me at the moment) or don’t mind writing a useful behaviour for all of us.

Sometimes one needs to do a SELECT ... FOR UPDATE in order to preserve the integrity of our transactions. The problem can be seen easily with the following example:

Suppose we have a user, an account table with the account.available_money field on it. Suppose the user has initially $100.

The problem arrives if the hacker manages to concurrently run two processes (only the relevant generated queries by find() and save() are shown) :

One process does:

BEGIN
SELECT available_money from account where user_id = '1' ; -- $money = $100
UPDATE account SET available_money = 0 where user_id = '1'; -- the user buy $100 and depletes his account
COMMIT

While another concurrent process does

-- php process _also_ finds $100 money so the user can user can use the $100 again it _again_
BEGIN
SELECT available_money from account  where user_id = '1'; // $money = $100
UPDATE account SET available_money = 0 where user_id = '1'; //the user buys _again_ $100 and he depletes his account
COMMIT

If this happens, then the user could use more money than he is entitled to. SELECT FOR UPDATE comes to the rescue. Following the previous example

One process does:

BEGIN
SELECT available_money from account  where user_id = '1' FOR UPDATE; // $money = $100
UPDATE account SET available_money = 0 where user_id = '1';
COMMIT

While another concurrent process does

BEGIN
SELECT available_money from account where user_id = '1'; // now this second process must wait the first process to finish, so $money = $0
-- the user doest not have money to buy anything
COMMIT

Now, how to achieve this using CakePHP ?

CakePHP’s dbo doesn’t currently support FOR UPDATE syntax. BUT there is a litlle quick and dirty (maybe too dirty for some) hack you can do without doing any modifications to the core ...

Since in the dbo_source, in the SELECT`statement, the `LIMIT clause gets parsed at last (see line 1497 from cake/libs/models/dbo_source.php):

switch (strtolower($type)) {
    case 'select':
        return "SELECT {$fields} FROM {$table} {$alias} {$joins} {$conditions} {$group} {$order} {$limit}";
    break;
    //...

If in a need, and if using PostgreSQL (mysql later), you could do

$transac = $this->AccountModel->find('all', array(
    'conditions' => array(
        'user_id' =>$id
    ),
    'fields' => array('available_money'),
    'limit' => 'ALL FOR UPDATE'
));`

... and this would generate the SELECT available_money from account where user_id = ‘1’ FOR UPDATE clause we are looking for... The trick is in the ‘limit’ => ‘ALL FOR UPDATE’. This selects ALL records that match the conditions FOR UPDATE.

For MySql you would have to do something a lot uglier. Since MySql doesn’t support LIMIT ALL, you would have to use LIMIT 0,18446744073709551615. This is pretty horrible , I know... The other options are to code a behavior for all of us : )

Just remember to put you find inside a transaction !

Watch out , there is a little (but important) catch... You can’t do find(‘first), since the LIMIT clause would be overwritten by Cake as LIMIT 1, instead you can do find(‘all’, ... ‘limit’ => ‘1 FOR UPDATE’ ...)

published on Apr 14, 2012 12:00 AM

Read more

Zhen CRM: open-source CakePHP CRM application

Zhen CRM: open-source CakePHP CRM application

A simple CRM built on CakePHP 2.x

We are pleased to announce the release of Zhen CRM, an open source CRM solution built on CakePHP.

Project page: http://telerim.github.com/Zhen-CRM/ GitHub project: https://github.com/telerim/Zhen-CRM

While this does not have the complicated features of enterprise CRMs, it has the basic features that most small businesses could use - such as contacts, tasks, “deals” and a calendar.

In contrast to the many other commercial CRM solutions available on the market, this is free, simple and can be installed on one’s own servers or shared hosts.

published on Apr 13, 2012 12:00 AM

Read more

CakeApp with TwitterBootstrap

CakeApp with TwitterBootstrap

CakeApp is a preconfigured app with TwitterBootstrap and Jquery installed and ready to go.

Twitter Bootstrap appears to be a very successful CSS framework, and I must agree. There is a js library that you can include which will help you get TB (Twitter Bootstrap) setup, but I wanted to take it one step further.

I created “CakeApp” Which is a CakeApp with some niceties already added in there for you. Including Jquery and a pre-configured TB, which should have everything as of 4/13/12. Also, the homepage has been updated to use TB, so you are running right out of the gate.

Here is a link to that: https://github.com/alairock/CakeApp

Enjoy, and fork if you want to contribute! -alairock

published on Apr 13, 2012 12:00 AM

Read more

Helper TinyMCE for CakePHP 2

Helper TinyMCE for CakePHP 2

Helper TinyMCE for CakePHP 2 with preset fuction.

TinyMCE

  1. Download TinyMCE : http://www.tinymce.com/download/download.php
  2. Copy /tinymce/jscripts/ tiny_mce folder to /app/webroot/js (like : /app/webroot/js/tiny_mce).

Controller

public $helpers = array('Tinymce');

Helper code

app/View/Helper/TinymceHelper.php

<?php
App::uses('AppHelper', 'View/Helper');

class TinymceHelper extends AppHelper {

    // Take advantage of other helpers
    public $helpers = array('Js', 'Html', 'Form');

    // Check if the tiny_mce.js file has been added or not
    public $_script = false;

    /**
    * Adds the tiny_mce.js file and constructs the options
    *
    * @param string $fieldName Name of a field, like this "Modelname.fieldname"
    * @param array $tinyoptions Array of TinyMCE attributes for this textarea
    * @return string JavaScript code to initialise the TinyMCE area
    */
    function _build($fieldName, $tinyoptions = array()){
        if(!$this->_script){
            // We don't want to add this every time, it's only needed once
            $this->_script = true;
            $this->Html->script('tiny_mce/tiny_mce', array('inline' => false));
        }

        // Ties the options to the field
        $tinyoptions['mode'] = 'exact';
        $tinyoptions['elements'] = $this->domId($fieldName);

        // List the keys having a function
        $value_arr = array();
        $replace_keys = array();
        foreach($tinyoptions as $key => &$value){
            // Checks if the value starts with 'function ('
            if(strpos($value, 'function(') === 0){
                $value_arr[] = $value;
                $value = '%' . $key . '%';
                $replace_keys[] = '"' . $value . '"';
            }
        }

        // Encode the array in json
        $json = $this->Js->object($tinyoptions);

        // Replace the functions
        $json = str_replace($replace_keys, $value_arr, $json);
        $this->Html->scriptStart(array('inline' => false));
        echo 'tinyMCE.init(' . $json . ');';
        $this->Html->scriptEnd();
    }

    /**
    * Creates a TinyMCE textarea.
    *
    * @param string $fieldName Name of a field, like this "Modelname.fieldname"
    * @param array $options Array of HTML attributes.
    * @param array $tinyoptions Array of TinyMCE attributes for this textarea
    * @param string $preset
    * @return string An HTML textarea element with TinyMCE
    */
    function textarea($fieldName, $options = array(), $tinyoptions = array(), $preset = null){
        // If a preset is defined
        if(!empty($preset)){
            $preset_options = $this->preset($preset);

            // If $preset_options && $tinyoptions are an array
            if(is_array($preset_options) && is_array($tinyoptions)){
                $tinyoptions = array_merge($preset_options, $tinyoptions);
            }else{
                $tinyoptions = $preset_options;
            }
        }
        return $this->Form->textarea($fieldName, $options) . $this->_build($fieldName, $tinyoptions);
    }

    /**
    * Creates a TinyMCE textarea.
    *
    * @param string $fieldName Name of a field, like this "Modelname.fieldname"
    * @param array $options Array of HTML attributes.
    * @param array $tinyoptions Array of TinyMCE attributes for this textarea
    * @return string An HTML textarea element with TinyMCE
    */
    function input($fieldName, $options = array(), $tinyoptions = array(), $preset = null){
        // If a preset is defined
        if(!empty($preset)){
            $preset_options = $this->preset($preset);

            // If $preset_options && $tinyoptions are an array
            if(is_array($preset_options) && is_array($tinyoptions)){
                $tinyoptions = array_merge($preset_options, $tinyoptions);
            }else{
                $tinyoptions = $preset_options;
            }
        }
        $options['type'] = 'textarea';
        return $this->Form->input($fieldName, $options) . $this->_build($fieldName, $tinyoptions);
    }

    /**
    * Creates a preset for TinyOptions
    *
    * @param string $name
    * @return array
    */
    private function preset($name){
        // Full Feature
        if($name == 'full'){
            return array(
                'theme' => 'advanced',
                'plugins' => 'safari,pagebreak,style,layer,table,save,advhr,advimage,advlink,emotions,iespell,inlinepopups,insertdatetime,preview,media,searchreplace,print,contextmenu,paste,directionality,fullscreen,noneditable,visualchars,nonbreaking,xhtmlxtras,template',
                'theme_advanced_buttons1' => 'save,newdocument,|,bold,italic,underline,strikethrough,|,justifyleft,justifycenter,justifyright,justifyfull,styleselect,formatselect,fontselect,fontsizeselect',
                'theme_advanced_buttons2' => 'cut,copy,paste,pastetext,pasteword,|,search,replace,|,bullist,numlist,|,outdent,indent,blockquote,|,undo,redo,|,link,unlink,anchor,image,cleanup,help,code,|,insertdate,inserttime,preview,|,forecolor,backcolor',
                'theme_advanced_buttons3' => 'tablecontrols,|,hr,removeformat,visualaid,|,sub,sup,|,charmap,emotions,iespell,media,advhr,|,print,|,ltr,rtl,|,fullscreen',
                'theme_advanced_buttons4' => 'insertlayer,moveforward,movebackward,absolute,|,styleprops,|,cite,abbr,acronym,del,ins,attribs,|,visualchars,nonbreaking,template,pagebreak',
                'theme_advanced_toolbar_location' => 'top',
                'theme_advanced_toolbar_align' => 'left',
                'theme_advanced_statusbar_location' => 'bottom',
                'theme_advanced_resizing' => true,
                'theme_advanced_resize_horizontal' => false,
                'convert_fonts_to_spans' => true,
                'file_browser_callback' => 'ckfinder_for_tiny_mce'
            );
        }

        // Basic
        if($name == 'basic'){
            return array(
                'theme' => 'advanced',
                'plugins' => 'safari,advlink,paste',
                'theme_advanced_buttons1' => 'code,|,copy,pastetext,|,bold,italic,underline,|,link,unlink,|,bullist,numlist',
                'theme_advanced_buttons2' => '',
                'theme_advanced_buttons3' => '',
                'theme_advanced_toolbar_location' => 'top',
                'theme_advanced_toolbar_align' => 'center',
                'theme_advanced_statusbar_location' => 'none',
                'theme_advanced_resizing' => false,
                'theme_advanced_resize_horizontal' => false,
                'convert_fonts_to_spans' => false
            );
        }

        // Simple
        if($name == 'simple'){
            return array(
                'theme' => 'simple',
            );
        }

        // BBCode
        if($name == 'bbcode'){
            return array(
                'theme' => 'advanced',
                'plugins' => 'bbcode',
                'theme_advanced_buttons1' => 'bold,italic,underline,undo,redo,link,unlink,image,forecolor,styleselect,removeformat,cleanup,code',
                'theme_advanced_buttons2' => '',
                'theme_advanced_buttons3' => '',
                'theme_advanced_toolbar_location' => 'top',
                'theme_advanced_toolbar_align' => 'left',
                'theme_advanced_styles' => 'Code=codeStyle;Quote=quoteStyle',
                'theme_advanced_statusbar_location' => 'bottom',
                'theme_advanced_resizing' => true,
                'theme_advanced_resize_horizontal' => false,
                'entity_encoding' => 'raw',
                'add_unload_trigger' => false,
                'remove_linebreaks' => false,
                'inline_styles' => false
            );
        }
        return null;
    }
}

Behavior

$this->Tinymce->input($Model.fieldName, $options = array(), $tinyoptions = array(), $preset = null)

Example

<div class="posts form">
<?php echo $this->Form->create('Post');?>
    <fieldset>
            <legend><?php echo __('Add Post'); ?></legend>
    <?php
            echo $this->Form->input('title');
            echo $this->Tinymce->input('Post.content', array(
                    'label' => 'Content'
                    ),array(
                            'language'=>'en'
                    ),
                    'bbcode'
        );
    ?>
    </fieldset>
<?php echo $this->Form->end(__('Submit'));?>
</div>

Thanks

http://bakery.cakephp.org/articles/daibach/2008/07/15/tinymce-helper-1 http://forum.cakephp-fr.org/viewtopic.php?id=1136

published on Apr 11, 2012 12:00 AM

Read more

Custom Fields Plugin for CakePHP 2.x

Custom Fields Plugin for CakePHP 2.x

A custom fields plugin for CakePHP 2.x. Now you can add custom fields to your CakePHP app and individual models/controllers without having to worry about database changes.

GitHub page: https://github.com/srs81/CakePHP-CustomFields

CustomFields Plugin for CakePHP

A custom fields plugin for CakePHP 2.x. Now you can add custom fields to your CakePHP app and individual models/controllers without having to worry about database changes.

How to Use

Download or checkout

You can either download the ZIP file:https://github.com/srs81/CakePHP-CustomFields/zipball/master

or checkout the code (leave the Password field blank):

git clone https://srs81@github.com/srs81/CakePHP-CustomFields.git

Put it in the Plugin/ directory

Unzip or move the contents of this to “Plugin/CustomFields” under the app root.

Add to bootstrap.php load

Open Config/bootstrap.php and add this line:

`php CakePlugin::load('CustomFields'); `

This will allow the plugin to load all the files that it needs.

Add the custom fields for the models

Add the custom fields for the model(s) that you want to add. For instance, say you want to add the fields “author” and “publish_at” to your “Blog” model and a “date_of_birth” to a “User” model, you would add this:

`php Configure::write('CustomFields', array( 'Blog' => 'author, publish_at', 'User' => 'date_of_birth' )); ` You can add this to either APP/Config/bootstrap.php or APP/Plugin/CustomFields/Config/bootstrap.php .

Create file directory

Make sure to create the correct files upload directory if it doesn’t exist already:<pre> cd cake-app-root mkdir webroot/files/custom_fields chmod -R 777 webroot/files/custom_fields</pre>

The default upload directory is “files/custom_fields” under /webroot - but this can be changed (see FAQ below.)

You don’t have to give it a 777 permission - just make sure the web server user can write to this directory.

Add to controller

Add to Controller/AppController.php for use in all controllers, or in just your specific controller where you will use it as below:

`php var $helpers = array('CustomFields.Field'); var $components = array('CustomFields.Field'); `

And to your add() / edit() functions, just after the ->save() function:

`php $this->Field->save("Blog", $this->request->data); `

Add to views

Let’s say you had a “blogs” table with a “id” primary key.

Add this to your View/Blogs/view.ctp:

`php echo $this->Field->view('Blog', $blog['Blog']['id']); `

and this to your View/Blogs/edit.ctp:

`php echo $this->Field->edit('Blog', $this->Form->fields['Blog.id']); `

FAQ

Dude! No database/table schema changes?

Nope. :) Just drop this plugin in the right Plugin/ directory and add the code to the controller and views. Make sure the “files/custom_fields” directory under webroot is created and writable, otherwise custom fields won’t save.

No tables/database changes are needed since the plugin uses a directory structure based on the model name and id to save the appropriate files for the model.

Change directory

Are you stuck to the “files/custom_fields” directory under webroot? Nope.

Open up Config/bootstrap.php under the Plugin/CustomFields directory and change the “CF.directory” setting.

ChangeLog

Version 1.0.0: April 10, 2012

Future Work

I would like to eventually store the custom data into the database instead of a file, but that would involve more CakePHP complexity, as well as an initiliaztion script from the developer to set up the plugin-specific DB table. But it would help with analytics/reporting and pulling bulk custom data easily (for reporting, etc.)

Support

If you find this plugin useful, please consider a donation to Shen Yun Performing Arts to support traditional and historic Chinese culture.

published on Apr 11, 2012 12:00 AM

Read more

Auth – inline authorization the easy way

Auth – inline authorization the easy way

I wrote a wrapper class to make inline authorization easier. Often times you want to check on certain roles inside an action or view and depending on the result display specific content or execute specific code. As an example we only want to display the “admin infos” box on the home screen for an admin. All other users should not see this box.

Auth.User.Role (with Role being an array of role ids)

3 We would need to check the session manually against the roles we want to grant access to. This can get pretty hairy with more than one role allowed (if admins and moderators are allowed to see this box for example).

Preparations

We first need to make the class usable by putting this in our /Config/bootstrap.php:

// these IDs match the role_ids in the DB
define('ROLE_SUPERADMIN', '1');
define('ROLE_ADMIN', '2');
define('ROLE_MOD', '3');
define('ROLE_USER', '4');

// enable the Auth class
App::uses('Auth', 'Tools.Lib');

I like to use constants as they are shorter than Configure::read(‘admin’) etc. But Configure would work just as fine.

Then we need to decide whether we use single role (cake default) or multi role Authorization. I usually always use multi-roles. Therefore the default case for the Auth class is exactly this. The session then contains: B0x1A1 If you use single roles, you’re Session array should look like this:

Auth.User.role_id (with role_id being the single role we want to check against)

In this case you should set the following constant manually in your bootstrap:

define('USER_ROLE_KEY', 'role_id');

“Former” usage

For comparison I will outline the manual and “outdated” way of authorization first:

// we want to make sure that piece is only visible to admins and moderators
if ($this->Session->read('Auth.User.role_id') == ROLE_ADMIN || $this->Session->read('Auth.User.role_id') == ROLE_MOD) {}

// or with multi-role
if (in_array(ROLE_ADMIN, (array)$this->Session->read('Auth.User.Role')) || in_array(ROLE_MOD, (array)$this->Session->read('Auth.User.Role'))) {}

Quite a lot to write...

Note: This also only works in controller/component and view/helper scope. You would have to use the static CakeSession::read() in order to make this work in the model/behavior one etc.

Usage

Now the fun part. The wrapper class can be found in the [Tools Plugin](https://github.com/dereuromark/tools/blob/2.0/Lib/Auth.php).

// Same thing as above
if (Auth::hasRoles(array(ROLE_ADMIN, ROLE_MOD)) {}

Now isn’t that nicer to write and read?

The default case is that if one of the roles is matched it will return true right away. If you want to connect them with AND instead of OR, you need to make the second param false:

// This only passed if the user has both roles!
if (Auth::hasRoles(array(ROLE_ADMIN, ROLE_MOD), false) {}

If we only want to check against a single role we could also use the shorthand:

if (Auth::hasRole(ROLE_MOD) {}

Advanced usage

You can also pass in the roles you want to check against. This can be useful if you want to check somebody else’s roles (and not your session roles). This can come in handy in CLI (command line / shell) environment and also in the admin backend.

if (Auth::hasRole(ROLE_MOD, $rolesOfThisUser) {}

And

if (Auth::hasRoles(array(ROLE_MOD, ROLE_USER), true, $rolesOfThisUser) {}

And there is more

There are also some convenience methods available. Instead of $uid = $this->Session->read(‘Auth.User.id’) you can just write

$uid = Auth::id(); // anywhere in your application

The roles can be fetched like this:

$myRoles = Auth::roles(); // string in single-role and array in multi-role context

Last but not least the user data:

$user = Auth::user(); // complete user array
$username = Auth::user('username'); // string: current username
...

Details

[Read the full article here][article]. [article]: http://www.dereuromark.de/2012/04/07/auth-inline-authorization-the-easy-way/

published on Apr 7, 2012 12:00 AM

Read more

AddressFinderHelper, a widget for cakephp 2.x forms

AddressFinderHelper, a widget for cakephp 2.x forms

This helper encapsulates a nice javascript, providing client side address autocomplete from google maps, geocoding, and reverse geocoding while drag’n’dropping the marker on the map.

The helper is based on http://tech.cibul.net/geocode-with-google-maps-api-v3/ - most of the credit goes to their script.

The code and usage instructions on Github:https://github.com/stefanomanfredini/AddressFinder-Helper—Plugin-for-cakephp-2

I started using cakephp 2.x quite recently - this is my first helper for cakephp 2.x.. suggestions are welcome!

published on Apr 6, 2012 12:00 AM

Read more

Minify plugin for CakePHP 2.0+

Minify plugin for CakePHP 2.0+

Minify is an application that combines multiple CSS or Javascript files, removes unnecessary whitespace and comments, and serves them with gzip encoding and optimal client-side cache headers. More info: http://code.google.com/p/minify For this plugin, the application Minify is inside Vendor

Installation

You can clone the plugin into your project (or if you want you can use as a submodule)

cd path/to/app/Plugin or /plugins
git clone https://github.com/maurymmarques/minify-cakephp.git Minify

Bootstrap the plugin in app/Config/bootstrap.php:

CakePlugin::load(array('Minify' => array('routes' => true)));

Configuration

Set the configuration file in your app/Config/core.php

Configure::write('MinifyAsset', true);

If you do not want to use compression, set false. Create a folder called “minify” in app/tmp/cache and give permission to read and write.

Usage

Enable the helper using the plugin syntax

class BakeriesController extends AppController {
    public $helpers = array('Minify.Minify');
}

This plugin uses HtmlHelper, and works virtually the same. In the view you can use something like:

echo $this->Minify->css(array('default', 'global'));
echo $this->Minify->script(array('jquery', 'interface'));

Observation

Minify is designed for efficiency, but, for very high traffic sites, Minify may serve files slower than your HTTPd due to the CGI overhead of PHP. See the FAQ and CookBook for more info. You can check the performance results using the networking tools of the Google Chrome or Mozilla Firefox with Firebug and YSlow

GitHub

Any criticism or suggestion is welcome on https://github.com/maurymmarques/minify-cakephp.

published on Apr 4, 2012 12:00 AM

Read more

PhpExcel helper for generating excel files

PhpExcel helper for generating excel files

PhpExcel consists only from one helper class that uses PHPExcel project (located in vendors) to generate excel files.

PHPExcel is a great library that can create XLS files. For more information see PHPExcel project homepage.

I added method for setting font and for easy table data adding (see example).

This plugin is for CakePHP 2.x

Short example: ` //Controller: public$helpers=array(‘PhpExcel.PhpExcel’); `

` //View: $this->PhpExcel->createWorksheet(); $this->PhpExcel->setDefaultFont(‘Calibri’,12);

//definetablecells $table=array( array(‘label’=>__(‘User’),’width’=>’auto’,’filter’=>true), array(‘label’=>__(‘Type’),’width’=>’auto’,’filter’=>true), array(‘label’=>__(‘Date’),’width’=>’auto’), array(‘label’=>__(‘Description’),’width’=>50,’wrap’=>true), array(‘label’=>__(‘Modified’),’width’=>’auto’) );

//heading $this->PhpExcel->addTableHeader($table,array(‘name’=>’Cambria’,’bold’= >true));

//data foreach($dataas$d){ $this->PhpExcel->addTableRow(array( $d[‘User’][‘name’], $d[‘Type’][‘name’], $d[‘User’][‘date’], $d[‘User’][‘description’], $d[‘User’][‘modified’] )); }

$this->PhpExcel->addTableFooter(); $this->PhpExcel->output(); ` Download the code from https://github.com/segy/PhpExcel

published on Apr 2, 2012 12:00 AM

Read more

CakeHtmlHelper speed up your site enabling html cache - Cakephp 2.x

CakeHtmlHelper speed up your site enabling html cache - Cakephp 2.x

I have rewrite the Matt Curry Html Cache Plugin. Taken from http://github.com/mcurry/html_cache – Cake’s core cache helper is great, but the files it outputs are PHP files, so it will never be as fast as straight HTML files. This HTML Cache Helper writes out pure HTML, meaning the web server doesnt have to touch PHP when a request is made. Okey, first you must have mod_rewrite enable to make the html cache working;

<IfModule mod_rewrite.c>
    RewriteEngine On

    RewriteCond %{REQUEST_METHOD} ^GET$
    RewriteCond %{DOCUMENT_ROOT}/cache/$1/index.html -f
    RewriteRule ^(.*)$ /cache/$1/index.html [L]

    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteRule ^(.*)$ index.php?/$1 [QSA,L]
</IfModule>

Now create the helper in the file View/Helper/CacheHtmlHelper.php

<?php
// Original idea from Matt Curry, rewritten by Eugenio Fage
App::uses('AppHelper', 'View/Helper');

App::uses('Folder', 'Utility');
App::uses('File', 'Utility');

class CacheHtmlHelper extends AppHelper {
    private $CacheHtmlStrategy=null;

    public function __construct(View $view, $settings = array()) {
        parent::__construct($view, $settings);
        $defaults=array('CacheHtmlStrategy'=>'CacheHtmlStrategy');
        $settings=array_merge($settings,$defaults);

        if(!class_exists($settings['CacheHtmlStrategy'])) $settings['CacheHtmlStrategy']='CacheHtmlStrategy';
        $this->CacheStrategy=new $settings['CacheHtmlStrategy']();
    }

    public function afterLayout($viewFile) {
            $this->CacheStrategy->save($this->request,$this->_View->output);
    }
}


class CacheHtmlStrategy{
    public function save($request,$content){
            $File = new File($this->url2file($request->url), true);
            $File->write($content);
    }

    public function url2file($url){
            $path=WWW_ROOT.'cache'.DS;
            $path.=implode(DS, array_filter(explode('/', $url))).DS;
            $path=str_replace('//','/',$path);
            return $path.'index.html';
    }

    public function rendercache($url=null){
            if(!$url){
                    if(isset($_SERVER['PATH_INFO']) && $_SERVER['PATH_INFO']){
                            $url=$_SERVER['PATH_INFO'];
                    }else{
                            return;
                    }
            }
            $file=cacheUrl2File($this->url2file($url));

            if(file_exists($file)){
                    $fp = fopen($file, 'r');
                    fpassthru($fp);
                    exit;
            }
    }
}

Now, each time you want to cache an action add the helper in the controller; function someaction(){ $this->helpers[]=’HtmlCache’; }

You could create your own cache strategy to save the files in diferents path or doing some crazy thing, for example: Config/Crazyhtmlcacheconfig.php

<?
class CrazyHtmlStrategy extends CacheHtmlStrategy{
    public function url2file($request){
            $path=WWW_ROOT.'cache2'.DS;
            $path.=implode(DS, array_filter(explode('/', $request->url))).DS;
            $path=str_replace('//','/',$path);
            return $path.'index.html';
    }
}

Then add in your bootstrap; config(‘Crazyhtmlcacheconfig’);

And when you add the helper

$this->helpers[‘HtmlCache’]=array(‘CacheHtmlStrategy’=>’CrazyHtmlStrat egy’);

You could also try to render the files using php instead of the .htaccess routing, just have to add this in the bootstrap;

// use CacheHtmlStrategy or the strategy that you are currently using
$cache=new CacheHtmlStrategy();
$cache->rendercache();

Cheers to all! Written by Eugenio Fage

published on Apr 1, 2012 12:00 AM

Read more

ToastyCMS a CMS for people who love bread that is baked twice

ToastyCMS a CMS for people who love bread that is baked twice

I have been building a CMS for personal use. I call it Toasty. It is a very simple tool with very basic features. It can be found at https://github.com/icompuiz/ToastyCMS

I didn’t follow any real software process so I lack documentation. I am still working on it but I am looking for some feedback.

I have included some getting started information https://github.com/icompuiz/ToastyCMS/blob/master/README

It is built on CakePHP 2.0.1.

I am thinking about reimplementing it with cakephp 2.1.1 and using more of the cakephp conventions like plugins to support extensibility.

So far the current version being used to manage this website http://ritglobalunion.com.

Tell me what you think.

published on Mar 28, 2012 12:00 AM

Read more

Eclipse Code Completion in views using $this

Eclipse Code Completion in views using $this

If you are having problems getting eclipse to autocomplete helpers in views. Try this Create this file ( helper_complete.php ) add to your app/View directory, refresh your project and all should work. ( it does for me anyway! ) Add in helpers as you need

PHP Snippet:

<?php
App::uses('AppHelper', 'Helper');
/**
 * this Helper
 *
 * @property Html $Html
 * @property Session $Session
 * @property Form $Form
 */
class this extends AppHelper
{
    var $Html;
    var $Session;
    var $Form;

    public function __contruct()
    {
            $this->Html = new HtmlHelper($View);
            $this->Session = new SessionHelper($View);
            $this->Form = new FormHelper($View);
    }
}

$this = new this();
?>

published on Mar 28, 2012 12:00 AM

Read more

PaginationRecall for CakePHP 2.x

PaginationRecall for CakePHP 2.x

Have you used PaginationRecall component with CakePHP 1.x and wonder why it doesn’t work with CakePHP 2.x? Searching for a way to keep the page or ordering of pagination? I changed the old PaginationRecall component of mattc so that it works under CakePHP 2.x. Here’s the changes code:

 `

<?php
/*
*PaginationRecallCakePHPComponent
*Copyright(c)2008MattCurry
*www.PseudoCoder.com
*
*@authormattc<matt@pseudocoder.com>
*@version2.0
*@licenseMIT
*Changedtocakephp2.xby
*
*/

classPaginationRecallComponentextendsComponent{
var$components=array('Session');
var$Controller=null;

functioninitialize(&$controller){
$this->Controller=&$controller;

$options=array_merge($this->Controller->request->params,
$this->Controller->params['url'],
$this->Controller->passedArgs
);
$vars=array('page','sort','direction','filter');
$keys=array_keys($options);
$count=count($keys);

for($i=0;$i<$count;$i++){
if(!in_array($keys[$i],$vars)||!is_string($keys[$i])){
unset($options[$keys[$i]]);
}
}

//savetheoptionsintothesession
if($options){
if($this->Session->check("Pagination.{$this->Controller->modelClass}.options")){
$options=array_merge($this->Session->read("Pagination.{$this->Controller->modelClass}.options"),$options);
}

$this->Session->write("Pagination.{$this->Controller->modelClass}.options",$options);
}

//recallpreviousoptions
if($this->Session->check("Pagination.{$this->Controller->modelClass}.options")){
$options=$this->Session->read("Pagination.{$this->Controller->modelClass}.options");
$this->Controller->passedArgs=array_merge($this->Controller->passedArgs,$options);
$this->Controller->request->params['named']=$options;
}
}
}
?>


`

published on Mar 27, 2012 12:00 AM

Read more

Force saving with when insert primary key value

Force saving with when insert primary key value

Have you ever try to make a save when you manually set the primary key value?? > By default Cakephp perform an update query, when in the fields array there is the primary key value set. <br > If we have a DB table, where the primary key is not an AI, but is a value generated by an algoritm, we need to force cakephp to make an insert into query instead an update this workaround use the beforeSave callback. > beforeSave is called after cakephp decide in the current saving process in an insert or an update. <h1>put this code in the app_model:< h1> ` publicfunctionbeforeSave($opt){ parent::beforeSave($opt); if(isset($opt[‘id’])&&$opt[‘id’]){ if(!isset($this->data[$this->name][$this->primaryKey])){ $this->data[$this->name][$this->primaryKey]=$opt[‘id’]; } } returntrue; } ` ><br >

When you need to force the save use this:

` $this->save( array( ‘Model’=>$fields ), array( ‘id’=>$newId ) ); ` ><br > Replace $fields with the array fields to save but NOT INSERT IN IT THE PRIMARY KEY VALUE. > Replace $newId with the value of the primary key < strong> ><br >

See the magic!

published on Mar 27, 2012 12:00 AM

Read more

Force saving with know primary key

Force saving with know primary key

At first, sorry for my bad english but i’m italian. i’m writing this article for illustrate how to force a save instead update when we insert in the save fields the model’s primary key value. this workaround use the beforeSave callback. At first time insert in the app_model this function:

> <code><span style=”color: #000000”> <br >publicfunctionbeforeSave($opt){ parent::beforeSave($opt); if(isset($opt[‘id’])&&!is_null($opt[‘id’])){ if(!isset($this->data[$this->name][$this->primaryKey])){ $this->data[$this->alias][$this->primaryKey]=$opt[‘id’]; } } returntrue; }

><br > so, when you make a save in your code use this: ><br > ` $this->save( array( ‘Model’=>$fields, ), array( ‘id’=>$newId ) ) ` ><br > replace $fields with the fields array but NOT INSERT IN IT THE PRIMARY KEY FIELD. replace $newId with the know value of the primary key. using the beforeSave validate workaround, the primary key will be set after cake has decided to perform an insert query, because there is not primary key set. So if we need to make an insert, but we want to set manually the primary key value, just using this method, avoid that cake make an update query.

published on Mar 26, 2012 12:00 AM

Read more

CakePHP 2.1.1 and 1.3.15 released

CakePHP 2.1.1 and 1.3.15 released

As usual, the CakePHP team is proud to deliver another bugfix/maintenance release in a timely fashion!

The CakePHP core team is proud to announce the immediate availability of CakePHP 2.1.1 [1] and 1.3.15 [2]. Both versions are a bugfix/maintenance releases. This is a short list of changes that can be expected in both versions:

2.1.1

  • session_cache_limiter() removed when starting a session, also remove setting P3P header
  • Updated the .htaccess files, make sure you update them in you apps as well.
  • Set::sort() now correctly sorts when using {s}.path
  • Fixed Session.cookieTimeout default behavior
  • Made Validation class more strict when checking values in list.
  • Used urldecode trailing pass arguments in the URL
  • Added missing ‘recursive’ option to DigestAuthenticate object.

1.3.15

  • Fixed an issue with find(count) and translated conditions.
  • Adding iPad and windows phone os as mobile clients.
  • Fixed Number::currency() when using custom formats and numbers between -1 and 1.
  • Fix a bug introduced when generating partial compatibility between 1.3 and 2.0 Cookies, where an empty valued key caused a PHP notice. Also, harden tests.
  • Fix header stripping in EmailComponent, it was aggressively stripping to: from text.
  • Fix EmailComponent::reset() not resetting delivery
  • Fix issues where nested HABTM associations would create duplicate content.

If you have not upgraded to 2.1.1 there is no better time than this. Our newest release is our most stable and feature-rich release yet, don’t miss out on all these yummy enhancements!

A huge thanks to all involved in terms of both contributions through commits, tickets, documentation edits, and those whom have otherwise contributed to the framework. Without you there would be no CakePHP.

Download packaged releases [3]

Links

published on Mar 26, 2012 12:00 AM

Read more

TreeLiHelper

TreeLiHelper

Helper para criar lista html com links nos nós sem filhos gerados por uma tree->generateTreeList() no cakephp 2.1 No controller coloque:

PHP Snippet:

<?php
public function index(){
    $this->loadModel('Model');
    $this->set('data',$this->Model->generateTreeList());
}
?>

na View:

PHP Snippet:

<?php
echo '<ul data-role="listview" data-divider-theme="a" data-inset="true">';
echo $this->TreeView->createTree($data,array('controller'=>'Categorias','action'=>'view'));
echo '</ul>';
?>

Crie um arquivo com o nome TreeLiHelper.php na pasta /app/View/Helper/ com o seguinte conteudo:

PHP Snippet:

<?php
App::uses('AppHelper', 'View/Helper');
class TreeLiHelper extends AppHelper {
    public $helpers = array('Html');
    public $link;
    public function createTree($tree,$link){
            $this->link = $link;
            $out = '';
            $count = 0;
            $buffer = null;
            foreach($tree as $id => $item){
                    $depth = strrpos($item, '_');
                    if ($depth === false) {
                            $depth = 0;
                            $clean_item = $item;
                    } else {
                            $depth = $depth + 1;
                            $clean_item = substr($item, strrpos($item, '_')+1);
                    }
                    if($buffer != null){
                            $out .= $this->makeLi($buffer,$depth,$id);
                    }
                    $buffer['item'] = $clean_item;
                    $buffer['depth'] = $depth;
            }
            $out .=$this->makeLi($buffer,0,$id);
            return $out;
    }

    protected function makeLi($buffer,$depth,$id){
            if($buffer['depth']==$depth){
                    $out = '<li>'.$this->makeLabel($buffer['item'],$id)."</li>\n";
            }elseif($buffer['depth']<$depth){
                    $out = '<li>'.$this->makeLabel($buffer['item'])."\n<ul>\n";
            }elseif($buffer['depth']>$depth){
                    $out = "<li>".$this->makeLabel($buffer['item'],$id)."</li>\n";
                    $diff = $buffer['depth']-$depth;
                    for($i=0; $i<$diff;$i++){
                            $out .= "</ul> \n </li>\n";
                    }

            }
            return $out;
    }

    protected function makeLabel($item, $id = null){
            if($id!=null){
                    $return = $this->Html->link($item, $this->mountLink($id));
            }else{
                    $return = $item;
            }
            return $return;
    }

    protected function mountLink($id){
            if(is_array($this->link)){
                    $link = $this->link;
                    $link[] = $id;
            }else{
                    $link = rtrim($this->link,'/').'/'.$id;
            }
            return $link;
    }

}
?>

published on Mar 15, 2012 12:00 AM

Read more

Redis DataSource for cakePHP 2

Redis DataSource for cakePHP 2

Redis Datasource build for cakePHP 2 and above. If you need to connect your application with Redis database (redis.io) , I published my Connector at github. Feel free to use it and improve it as well. > <a href=”https: /github.com/nnset/Cake-PHP-2.xx-Redis-datasource”> Download from github

published on Mar 15, 2012 12:00 AM

Read more

Don't forget afterFind callback

Don’t forget afterFind callback

Many beginners like me ask something like, how could I get total comments count for a post? of course, there are many answers, but the most easier answer is ” Don’t forget afterFind callback in your Post model!

Suppose that you have Post and Comment model where Post model hasMany Comment while Comment model is belongsTo Post. Now we want to find all posts and each post’s comment count, we may do the following code in posts_controller:

function index(){
   $this->Post->unbindModel(array('hasMany' => array('Comment')), false);
   // Notice the above line
   $posts = $this->Post->find('all');
   $this->set('posts', $post);
}

We used unbindModel method to improve performance by stopping non required database queries to the Comment model. Now lets we look at the magic of afterFind in our Post model:

function afterFind($results, $primary = false) {
parent::afterFind($results, $primary);
foreach($results as $key => $val){
  if (isset($val['Post']['id'])){
    $results[$key]['Post']['commentsCount'] = $this->Comment->find('count', array('conditions' => array('Comment.post_id' => $results[$key]['Post']['id'])));
  }
}
return $results;
}

In the above code, we could able to add new key -commentsCount- to the Post result array and its value is retrieved from the Commen model. Using this solution we could able to do the following in the index view:

<?php foreach ($posts as $post): ?>
<h1><?php echo $post['Post']['title'];?></h1>
<span>There are <?php echo $post['Post']['commentsCount'];?> comments for this post</span>
<div><?php echo $post['Post']['content'];?></div>
<?php endforeach; ?>

I tested this code using CakePHP 1.2.11 and the following is the documentation link for afterFind callback:http://book.cakephp.org/1.2/en/view/681/afterFind

I hope this article to be useful for you and it is clear that it may be applied for any hasMany relations.

published on Mar 15, 2012 12:00 AM

Read more

AjaxMultiUpload Plugin for Cake 2.0.x and 2.1

AjaxMultiUpload Plugin for Cake 2.0.x and 2.1

A full-blown AJAX file uploader plugin for CakePHP 2.0.x and 2.1. Using this, you can add multiple file upload behavior to any or all of your models without having to modify the database or schema.

AjaxMultiUpload Plugin for CakePHP

A full-blown AJAX file uploader plugin for CakePHP 2.0.x and 2.1. Using this, you can add multiple file upload behaviour to any or all of your models without having to modify the database or schema.

You can click on the Upload File button, or drag-and-drop files into it. You can upload multiple files at a time without having to click on any button, and it shows you a nice progress notification during uploads.

How to Use

Download or checkout

You can either download the ZIP file:https://github.com/srs81/CakePHP-AjaxMultiUpload/zipball/master

or checkout the code (leave the Password field blank):

` git clone https://srs81@github.com/srs81/CakePHP-AjaxMultiUpload.git `

Put it in the Plugin/ directory

Unzip or move the contents of this to “Plugin/AjaxMultiUpload” under the app root.

Add to bootstrap.php load

Open Config/bootstrap.php and add this line:

`php CakePlugin::load('AjaxMultiUpload'); `

This will allow the plugin to load all the files that it needs.

Create file directory

Make sure to create the correct files upload directory if it doesn’t exist already:<pre> cd cake-app-root mkdir webroot/files chmod -R 777 webroot/files</pre>

The default upload directory is “files” under /webroot - but this can be changed (see FAQ below.)

You don’t have to give it a 777 permission - just make sure the web server user can write to this directory.

Add to controller

Add to Controller/AppController.php for use in all controllers, or in just your specific controller where you will use it as below:

`php var $helpers = array('AjaxMultiUpload.Upload'); `

Add to views

Let’s say you had a “companies” table with a “id” primary key.

Add this to your View/Companies/view.ctp:

`php echo $this->Upload->view('Company', $company['Company']['id']); `

and this to your View/Companies/edit.ctp:

`php echo $this->Upload->edit('Company', $this->Form->fields['Company.id']); `

FAQ

Dude! No database/table schema changes?

Nope. :) Just drop this plugin in the right Plugin/ directory and add the code to the controller and views. Make sure the “files” directory under webroot is writable, otherwise uploads will fail.

No tables/database changes are needed since the plugin uses a directory structure based on the model name and id to save the appropriate files for the model.

Help! I get file upload or file size error messages!

The default upload file size limit is set to a conservative 2 MB to make sure it works on all (including shared) hosting. To change this:

  • Open up Plugin/AjaxMultipUpload/Config/bootstrap.php and change the “AMU.filesizeMB” setting to whatever size in MB you like.
  • Make sure to also change the upload size setting ( upload_max_filesize and post_max_size) in your PHP settings ( php.ini) and reboot the web server!

Change directory

Are you stuck to the “files” directory under webroot? Nope.

Open up Config/bootstrap.php under the Plugin/AjaxMultiUpload directory and change the “AMU.directory” setting.

The directory will live under the app webroot directory - this is as per CakePHP conventions.

Change directory paths

Coming soon.

Future Work

  • Deleting files is not supported in this version.

Thanks

This uses the Ajax Upload script from: http://valums.com/ajax-upload/ and file icons from: http://www.splitbrain.org/projects/file_icons

Support

published on Mar 12, 2012 12:00 AM

Read more

CakePHP 2.1.0 just landed

CakePHP 2.1.0 just landed

Checkout the new version on the popular PHP framework. Cool surprises included!

The CakePHP core team is very excited to announce the immediate availability of CakePHP 2.1.0 stable. As noted in the previous releases, this version is fully backwards compatible with 2.0.6, making it a breeze to update your apps to start taking advantage of the many improvements that made into this release. We are not going to release any new versions for the 2.0.x branch, and any future bug fix will be done into the 2.1 branch.

In total, there were over 90 commits and a few minor enhancements added to this final release, since our last candidate. A complete list of the changes can be viewed in the changelogs page [2]. This is a quick list of version 2.1 highlights.

Content Type Views

Two new view classes have been added to CakePHP. The new JsonView and XmlView allow you to more easily generate XML and JSON views.

Extending views

The View class has a new method allowing you to wrap or ‘extend’ a view/element/layout with another file.

Plugin.view

All layout/view/element names can now use Plugin.view to indicate that a plugin view should be used. The plugin option for View::element() is deprecated.

Improved errors

The debug() function output is now cleaner and more readable. We have also added interactive stack traces to exception pages.

General purpose event system

A new, generic event system has been built and it replaces the way callbacks are dispatched. You can dispatch your own events and attach callbacks to them at will.

Testing

Fixtures can be created in datasources other than $test.

A new TestShell has been added. It reduces the typing required to run unit tests, and offers a file path based UI:

::
Console/cake test app/Model/Post.php Console/cake test app/Controller/PostsController.php

Callback priorities

Callbacks for Helpers, Behaviors, and Components now support priorities, this helps more easily control the order in which callbacks are fired.

ThemeView is now deprecated

We’ve merged all the ThemeView functionality into the View class. Easier theme support!

Improved HTTP caching

Added several new methods in CakeResponse class to fine-tune options for HTTP caching. RequestHandlerComponent will now stop the view rendering process if it detects the client has a cached version of the resource.

Most helpers converted to utility libs

We have now refactored some helpers into libraries like CakeTime and CakeNumber. Importing one of those libs is as easy as App::uses(‘String’, ‘Utility’) and use it as follows String::truncate($text);

Deep saving

saveAll and friends ( saveMany, saveAssociated, validateAssociated ...) now accept a new deep option param. For instance you can save the Author, Posts and related comments in just one call. You can also set the fieldList option to these methods, to provide a set of fields that are allowed to be saved.

New ACL engine

In addition to the good old database ACL engine, we have added a new one based on configuration files. This is a great alternative to the database solution for those who want to get a speedy permissions checking system when not requiring a database to dynamically manage permissions.

HtmlHelper::media()

The HtmlHelper gained a new media() method to generate HTML5 compatible audio and video tags with support for multiple alternate sources.

Other improvements and changes

  • Updated minimum PHP version requirement to 5.2.8 due to PHP bugs #44251 and #45748
  • Paginator helper now accepts an option to set the default class for the “current” page link
  • Extending non-existing views will throw an exception
  • Extending views using an absolute path (relative to the View folder) is now possible
  • Most view files in the cake core such as home.ctp and the default layout were moved into the app folder.
  • Query params are now shown in database log when using prepared statements
  • Transaction commands (BEGIN, COMMIT, ROLLBACK) are now shown in database log
  • Added Set::nest() and Set::get(). The former is used to created a nested array out of a plain one using an array key as reference. Set::get() is used to access any array value using dot notation.
  • Added Router::defaultRouteClass() to get/set the default Route class. This makes it easy to set a global default, useful for slug routes or i18n.
  • I18n::translate() now accepts a new $language param. It also now exposes methods to read .po files, useful for custom translation interfaces.`
  • Authenticate objects can now receive a ‘recursive’ option to limit data returned in queries used for finding users.
  • <!–nocache–> tags now work inside elements correctly.
  • FormHelper now omits disabled fields from the secured fields hash. This makes working with SecurityComponent and disabled inputs easier.
  • The between option when used in conjunction with radio inputs, now behaves differently. The between value is now placed between the legend and first input elements.
  • The hiddenField option with checkbox inputs can now be set to a specific value such as ‘N’ rather than just 0.
  • The for attribute for date + time inputs now reflects the first generated input. This may result in the for attribute changing for generated datetime inputs.
  • When using Media view setting the extension variable is now optional. If not provided its extracted from the id (aka filename)

One of the cool suprises we were saving for you, is the addition of a new site to the CakePHP domain. The new plugins repository site [4] aims to be the single reference and search start point for any extensions, plugins and applications done using CakePHP. Check it out at http://plugins.cakephp.org

Additionally we have done a major facelift to the CakePHP homepage [4] and the online manual [5], which among other cool things, have a fluid layout that will adapt to smaller screen sizes such as your mobiles phones or tablets. We are still working hard to get the rest of the sites done to match our new look.

For those wanting to ease deployment process of your cakephp applications, we have created our new PEAR channel [6] for the framework. This will help you keep up-to-date with new security fixes and latest enhancements. Just go to the website and follow the instructions!

As always, thanks to the friendly CakePHP community for the patches, documentation changes and new tickets. Without you there would be no CakePHP!

  • Download a packaged release [1]
  • View the changelog [2]

Links

published on Mar 5, 2012 12:00 AM

Read more

CakePHP internationalization and localization

CakePHP internationalization and localization

One of the best ways for your applications to reach a larger audience is to cater for multiple languages. This can often prove to be a daunting task, but the internationalization and localization features in CakePHP make it much easier and better one of the advantages of CakePHP is Internationalization and Localization with static translations in gettext style or dynamic translations of model data and It’s a good idea to serve up public content available in multiple languages from a unique url – this makes it easy for users (and search engines) to find what they’re looking for in the language they are expecting. There are several ways to do this, it can be by using language specific subdomains (en.example.com, fra.example.com, etc.), or using a prefix to the url such as is done with this application. You may also wish to glean the information from the browser’s user- agent, among other things.

First, it’s important to understand some terminology. Internationalization refers to the ability of an application to be localized. The term localization refers to the adaptation of an application to meet specific language (or culture) requirements (i.e., a “locale”).

1-Part: First of all you need to change the Security.salt value of the config/core.php to a different value, and then create the file /app/config/config.php for inserting the languages you want to display. In this article I’ll use English and Spanish, and the default language is English.

PHP Snippet:

<?php
<?php

/* add language to the file*/

$config['LANGUAGE'] = array(‘supported’ => array(‘eng’, ‘spa’),

‘default’   => ‘eng’);
?>

Internationalization and localization are often abbreviated as i18n and l10n respectively,

Why CakePHP use i18n or L10n?

because The terms are frequently abbreviated to the numeronyms i18n (where 18 stands for the number of letters between the first i and last n in internationalization, a usage coined at DEC in the 1970s or 80s) and L10n respectively, due to the length of the words. The capital L in L10n helps to distinguish it from the lowercase i in i18n.

You need to know your own language abbreviation. Here is the list of languages and the abbreviation of them:

cake/libs/l10n.php

Note:The three-character locale codes conform to the ISO 639-2 standard, although if you create regional locales (en_US, en_GB, etc.) cake will use them if appropriate.if you use The three-character locale code it will locale as a fallback if it doesn’t exist add it manually like this

$this->Session->write(‘Config.language’, ‘eng’);

For loading the configuration in your application, you need to append the following code at the end of file config/core.php

PHP Code

PHP Snippet:

<?php
<?php

Configure::load(‘config’);?>
?>

2-Part: The language files in CakePHP have either the extension .po or .mo. In this tutorial I’ll use .po files.

For getting more information you can refer to this article:

Localizing PHP Applications series Abouzekry wrote. http://phpmaster.com/localizing-php-applications-1 Note: Remember that po files are useful for short messages, if you find you want to translate long paragraphs, or even whole pages – you should consider implementing a different solution which we skip in this article

We create this folders:

app/locale/eng app/locale/spa For this tutorial, we will use translation for “messages”, so each language folder we have a sub folder names LC_MESSAGES (in uppercase).

Now we should have this:

app/locale/eng/LC_MESSAGES/default.po

app/locale/spa/LC_MESSAGES/default.po

Now that this step is finished, we can move on to the next step.

3-Part: In order to work with CakePHP’s text function (ie : __() ..etc ..) first we need to describe them , in fact The __() function identifies these strings as translatable text that will differ by language locale and uses the text within the __() function as the message ID. If we define the translations for a certain language, those translations will appear in place of these functions. If we do not define the translations for that language, the text within the __() function will display instead by default. Every word or phrase to translate is composed of a pair id-string the id is the “msgid” value and the string is the “msgstr” value.

Your Spanish PO file should look like this:

CODE

msgid “bienvenida”

msgstr ” En varios idiomas-tutorial por Alireza.”

msgid “congrat”

msgstr ” le da las gracias”

We now need to make a fake controller to switch between languages. It’s role consists of calling the AppController::beforeFilter() method when a user wants to switch languages.

Create the controller in app/controllers/switchto_controller.php using the following code:

PHP Snippet:

<?php
<?php

class SwitchtoController extends AppController {

var $uses = array();

var $name = ‘Switchto’;

function beforeFilter()

{

parent::beforeFilter();

}

}



The AppController needs some modifications; edit the controller so it looks like this:

<?php

class AppController extends Controller

{

function beforeFilter()

{

if($this->_checkLanguage())

$this->redirect($this->referer(), null, true);

}

function _checkLanguage()

{

if(!$this->Session->check(‘Config.language’) || $this->name == “Switchto”) {

$default_lang   = Configure::read(‘LANGUAGE.default’);

$supported_lang = Configure::read(‘LANGUAGE.supported’);

$lang = null;

if($this->name == “Switchto”)

$lang = $this->action;

// we need the Cookie

App::Import(‘Component’, ‘Cookie’);

$cookie = & new CookieComponent;

$cookie->time   = ‘+360 days’;

$cookie->name   = ‘MYAPP’;

$cookie->domain = ”;

$cookie->key    = ‘whatever-key-you-wish’;

$cookie->startup();

if(!class_exists(“L10n”))

uses(‘l10n’);

$l10n = & new L10n();

if(!$lang || !in_array($lang, $supported_lang))

{

if($cookie->read(‘tutolanguage.lang’) )

{

$lang = $cookie->read(‘tutolang/lang’);

if(!in_array($lang, $supported_lang))

$lang = null;

}

/* try to find a language spaom browser that we support */

if(!$lang)

{

$browserLang = split (‘[,;]‘, env(‘HTTP_ACCEPT_LANGUAGE’));

foreach($browserLang as $langKey )

{

if(isset($l10n->__l10nCatalog[$langKey]) &&

in_array($l10n->__l10nCatalog[$langKey]['locale'], $supported_lang) )

{

$lang = $l10n->__l10nCatalog[$langKey]['locale'];

break;

}

}

}

}

if(!$lang)

$lang = $language_default;

// set the language, and write in cookie

$l10n->__setLanguage($lang);

$cookie->write(array(‘tutolanguage.lang’ => $lang));

$this->Session->write(‘Config.language’,$lang);

if($this->name == “Switchto”)

return true;

}

return false;

}

}

 ?>

In order to remember the language selected by the user, we will use cookies and so I’ve imported the Cookie component. I’ve chosen to integrate the cookie this way instead of declaring it in $components in order to avoid the overhead on the component in every call.

Explanations for _checkLanguage method:

The method work in 2 cases only: “when no session language is set” and “when user wants to switch language”. This is handling by the first condition statement. We get our supported languages and the default one from the configuration. If the controller is “SwitchTo”, it’s because the user clicks on a link to change the language. Then the action will be our language chosen (see below how to set a link to handle language switching. We suppose the desired language is the action name. Next we import the Cookie component. Indeed in order to remember the language we use cookies,I have used this way to integrate the cookie instead of declaring it in the $components in order to avoid the overhead on the component in every call(I test it ). We set the cookie parameters, you may change this to your own setting. Note that the call to $cookie->startup is essential to have the expiration date properly initialized. We will use the class L10n for setting our language. We instantiate an object of this class. We verify that our desired language is supported (either the desired is null, or set by the SwitchTo action. If the language is not supported we look if we have it in the cookie. If so we still verify we support it (that can happen in case or a removal of a language). In case we did not have any language, we verify if one of the browser supported language is matching one of our supported language. If so, we will use the first one matching. Still no language defined, then we will use our application default’s language. We use the L10n _setLanguage method to set our language application wide and we set our session language (missing this will screw up the process). We write the language in the cookie. When a user comes back, he will be automatically set to the last language he was. We return true in case of a deliberated language switch in order the beforeFilter to redirect to the referrer URL. The beforerFilter is self-explanatory, we redirect to the referrer in case the user did choose another language.

4-Part: A sample main page

To test the example, I modified the cake default main page (copy from cake distribution and place it in app/views/pages/display.ctp

PHP Snippet:

<?php
<h2><?php __(” bienvenida”); ?></h2>

<br />

<ul>

<li><?php echo $html->link(‘English’, ‘/switchto/eng’);?></li>

<li><?php echo $html->link(‘Spanish’, ‘/switchto/spa’);?></li>

</ul>

<br />

<h3><?php echo __(“congrat”, true);?><h3>

 ?>

The file demonstrates two ways in which the __() function is used. In either case, the first argument is a value that matches a msgid in the default.po file. if the msgid is not found in the PO file, then the value will be returned as is. By default, the translation message (or the unmatched msgid) will be outputted to the user. But __() also supports a second optional Boolean parameter which you can use if you want to capture the output instead of sending it, perhaps to pass to another function or anything else you may need to do to it.

It’s worth noting the language files are cached into the tmp/cache/persistent/cake_core_default_xxx files (where xxx is the locale). When using cake with debug = 0, be sure to delete the cached language file in order to reflect the changes immediately.

5-Part: Summery When it comes to internationalization and localization your web application, you may have a lot of options but CakePHP will be the best choice . in fact using cookie instead of subdomain and other ways or using translations in gettext style have lots of advantages which we will find in this article and CakePHP make it rapid and more flexible to create your applicatio

published on Mar 2, 2012 12:00 AM

Read more

Report Manager Plugin for CakePHP 2

Report Manager Plugin for CakePHP 2

The report manager plugin can help users to create reports based on application models.

Changelog for version 0.4.5

  • bugfix: delete saved report does not refresh the list properly
  • bugfix: array index errors on loading reports

Changelog for version 0.4.4

  • enhancement: JS changes to work on non-root URLs

Changelog for version 0.4.3

  • bugfix: default.js : update after renumber position

Changelog for version 0.4.2

  • bugfix: order.ctp - test if OrderBy1 and OrderBy2 are set
  • bugfix: ReportsController listReports method - handle empty array

Changelog for version 0.4

  • Load and Save reports
  • Export to XLS

Changelog for version 0.3

  • One to many reports
  • Sortable fields by drag and drop ( step 1 )
  • Click to add field change background color ( step 1 )
  • Click in model name check/uncheck all fields ( step 1 )
  • SmartWizard validation ( step 1 )
  • Datepicker for date fields ( step 2 )
  • Checkbox to enable counter option ( step 4 )
  • Check box for one to many reports : show items with no related records ( step 4 )
  • Both jquery and jquery ui libraries are loaded from google

Installation

  1. Download the plugin from github or sourceforge ( where you can see some screenshots )

https://sourceforge.net/projects/repomancakephp/

https://github.com/luisdias/CakePHP-Report-Manager-Plugin

  1. Extract the zip file on the app/Plugin folder ( the plugin folder must be named ReportManager )
  2. Add the following line to your bootstrap.php file ( located at app/Config folder )

CakePlugin::load(‘ReportManager’,array(‘bootstrap’ => true));

  1. Go to the url http://mycakeapp/report_manager/reports to see the main page listing all models

Using the plugin

The wizard interface is self explanatory.

  1. On the first tab you can select the fields and their position
  2. On the second tab you can define a filter
  3. On the third tab you can select up to two fields to sort
  4. On the last tab you can enter a name for your report and choose between 5 style options

Configuration:

Some parameters could be configured in the app/Plugin/ReportManager/Config/bootstrap.php

  • Display foreign keys
  • Ignore List for global fields ( affects all models )
  • Ignore list for models
  • Ignore list for specific model’s fields
  • Reports directory path

Notes:

It was inspired by the Report Creator Component by Gene Kelly from Nov 9th 2006.

http://bakery.cakephp.org/articles/Gkelly/2006/11/09/report-creator-component

It also uses a Jquery plugin called SmartWizard by Tech Laboratory.

http://techlaboratory.net/products.php?product=smartwizard

Since version 0.3 the Report Manager Plugin load the jQuery and jQuery UI libraries from Google

Collaborators:

Suman (USA)

Santana (Brazil)

Tamer Solieman (Egypt)

jasonchua89

Author: Luis E. S. Dias

Contact: smartbyte.systems@gmail.com

published on Feb 23, 2012 12:00 AM

Read more

Sphinx Search Behavior for Cake 2.0+

Sphinx Search Behavior for Cake 2.0+

I’ve updated the previous CakePHP behavior to work for Cake 2.0, and also optimized it down to one query, versus two

https://github.com/nshahzad/Sphinx-CakePHP

published on Feb 21, 2012 12:00 AM

Read more

CakePHP 2.1 Release Candidate is out

CakePHP 2.1 Release Candidate is out

The first, and hopefully only, release candidate for CakePHP 2.1 was released. If you have an application running on 2.0 or planning to migrate, this is the best moment to start checking this version out!

The CakePHP core team is proud to announce the immediate availability of the first CakePHP 2.1.0 Release Candidate [1]. As noted in the previous releases, this version is fully backwards compatible with 2.0.6, making it a breeze to update your apps to start taking advantage of the many improvements that made into this release. This will hopefully be the only release candidate for the branch, should any serious bugs arise we will keep offering release candidates until we reach stable.

In total, there were over 170 commits and over 4 new major features or enhancements added to this release candidate, in addition to the previous 2.1 beta release. A complete list of the changes can be viewed in the changelogs page [2]. This is a quick list of this version’s main highlights:

Most helpers converted to utility libs

One common feature request was to be able to use methods from the Text, Time and Number helpers outside views. Valid uses for the methods exposed in those helpers are email sending in shells, data formatting before saving in models and a few other cases in controllers. We have now refactored those helpers into libraries CakeTime and CakeNumber, while all methods found in the Text helper were placed into the String class.

Importing one of those libs is as easy as App::uses(‘String’, ‘Utility’) and use it as follows String::truncate($text);

All new libraries are composed of static methods, no need to instantiate the class. Additionally, refactored helpers will still work as usual, but they now rely in the underlying libs to function. This opens up the posibility of swapping the “engine” those helpers are using to produce the same results in views.

Deep saving

saveAll and friends ( saveMany, saveAssociated, validateAssociated ...) now accept a new deep option param. If you set this param to true the it will save data as deep as it can, bringing the posibility of saving any level of data nesting you like in a single transaction. For instance you can save the Author, Posts and related comments in just one call.

The aforementioned functions also accept a fieldList option to specify which of those fields should be saved or validated. This list will apply to deep associations too.

New ACL engine

In addition to the good old database ACL engine, we have added a new one based on configuration files. This engine takes a php file containing specific variables describing AROS, ACOS and permissions to grant access to resources in your application. This is a great alternative to the database solution for those who want to get a speedy permissions checking system when not requiring a database to dynamically manage permissions.

HtmlHelper::media()

The HtmlHelper gained a new media() method to generate HTML5 compatible audio and video tags with support for multiple alternate sources.

Other improvements and changes

  • Updated minimum PHP version requirement to 5.2.8 due to PHP bugs #44251 and #45748
  • Paginator helper now accepts an option to set the default class for the “current” page link
  • Extending non-existing views will throw an exception
  • Extending views using an absolute path (relative to the View folder) is now possible
  • Most view files in the cake core such as home.ctp and the default layout were moved into the app folder.
  • Query params are now shown in database log when using prepared statements

We’re almost ready with this version and we have a couple of surprises for the community, so stay tuned! As always, thanks to the friendly CakePHP community for the patches, documentation changes and new tickets. Without you there would be no CakePHP!

  • Download a packaged release [1]
  • View the changelog [2]

Links

published on Feb 20, 2012 12:00 AM

Read more

reCAPTCHA Plugin for CakePHP 2

reCAPTCHA Plugin for CakePHP 2

I have updated and improved tbsmcd’s reCAPTCHA Plugin for CakePHP2. https://github.com/Jahdrien/ReCaptcha-Plugin

1. Get reCAPTCHA key.

http://www.google.com/recaptcha

2. Setting.

Download recaptchalib.php. And put it in “Recaptcha/Vendor”. http://code.google.com/p/recaptcha/downloads/list?q=label:phplib- Latest

3. Config.

Insert keys in Recaptcha/Config/key.php . $config = array( ‘Recaptcha’ => array( ‘Public’ => ‘xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx’, ‘Private’ => ‘xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx’, ), );

4. Bootstrap.

if you load your plugins one by one add CakePlugin::load(‘Recaptcha’);

ReCaptcha/Config/bootstrap.php only reads your key.php config file

5. Controller.

public $components = array(‘Recaptcha.Recaptcha’); public $helpers = array(‘Recaptcha.Recaptcha’);

or inside controller action

$this->helpers[] = ‘Recaptcha.Recaptcha’; $this->Components->load(‘Recaptcha.Recaptcha’)->startup($this);

always add in your controller action or in bootstrap Configure::load(‘Recaptcha.key’);

6. View.

Inside <form> tags: echo $this->Recaptcha->show(array $options); $options : any recaptcha supported option (theme, lang, custom_translations, custom_theme_widget, tabindex) example: echo $this->Recaptcha->show(array( ‘theme’ => ‘white’, ‘lang’ => ‘fr’, ));

echo $this->Recaptcha->error();

published on Feb 15, 2012 12:00 AM

Read more

ThumbnailHelper, a thumbnail generator with cache dynamic

ThumbnailHelper, a thumbnail generator with cache dynamic

A helper that generates thumbnails of images and uses a cache to store them.

On every site I’ve ever worked had the problem of image thumbnails, because we always have to have thumbnails of certain images to display them in views in cakephp was no different. I found the behavior that makes MeioUpload everywhere upload images, but it uses to generate the thumbnails phpThumb but I could not use it in any way without mentioning that it would generate the thumbnail image at the time of upload, but often need these miniatures in several different sizes and is not feasible to create several thumbnails, so I created a helper that “serves” these thumbnails according to the passed parameters such as size, height, quality and cutting method, where he serves as a miniature based on these parameters it creates a cache of the image thus forming her only once, saving resources and increasing server performance. The use of ThumbnailHelper looks like this:

//I declare the helper in
public $helpers = array('Html', 'Thumbnail');

//updated echo $this->Thumbnail->render(‘teste.jpg’, array( ‘path’ => ‘’, ‘width’ => ‘100’, ‘height’ => ‘100’, ‘resizeOption’ => ‘portrait’, ‘quality’ => ‘100’ ), array(‘id’ => ‘img-test’, ‘alt’ => ‘thumbnail test’));

To download the helper visit my github, make a clone of the repository folder inside the app/View/Helper.

https://github.com/emersonsoares/ThumbnailsHelper-for-CakePHP

published on Feb 13, 2012 12:00 AM

Read more

User Management Plugin for cakephp 2.x

User Management Plugin for cakephp 2.x

Hey I have launched a new user management plugin for cakephp 2.x checkout demo Free Version http://usermgmt.ektasoftwares.com/ Premium Version http://umpremium.ektasoftwares.com/ Download from Github https://github.com/chetanvarshney/User-Management-Plugin-for- Cakephp-2.x

UserMgmt is a User Management Plugin for cakephp 2.x Plugin version 1.0 (now stable)

Hey wanna Demo???

Free Version here is http://usermgmt.ektasoftwares.com/

Premium Version here is http://umpremium.ektasoftwares.com/

Main Features- 1. Clean code with formatting 2. Login 3. Registration 4. Cookie login/ Remember me functionality 5. Add/Edit/Delete User By Admin 6. Add/Edit/Delete Group By Admin 7. Change Password 8. Forgot Password 9. Change User Password by Admin 10. List of all Users 11. List of all Groups 12. Manage site Permissions using Ajax updation, Permission caching functionality for fast checking 13. User’s Email Verification 14. User Profile View 15. User activation by Admin 16. Routing long urls to small urls

It’s based on jedt/SparkPlug plugin

checkout demo

http://usermgmt.ektasoftwares.com/

http://umpremium.ektasoftwares.com/

Download from Github https://github.com/chetanvarshney/User-Management-Plugin-for-Cakephp-2.x

published on Feb 11, 2012 12:00 AM

Read more

Custom RSS-Helper that actually works with namespaces for Cakphp 2.0

Custom RSS-Helper that actually works with namespaces for Cakphp 2.0

I had a hard time using cakes built in rss helper to create a podcast- feed for iTunes/iTunes U, because Apple wants us to use custom tags defined in their own namespace. Namespaces don’t work with cakes rss helper (for now), so I built my own!

I’ve described my problems in this thread over in the cakephp google group.

My own solution consists of a very simple little helper class which I posted to the bin: Cakephp bRss Helper

For how to use it have a look at the official cakebook here.

But unlike there, use this layout and this view. Note how I ignore the ‘documentData’ and create the surrounding rss tag with the necessary namespace information “by hand”.

Also my helper just constructs the xml as a string without ever using php’s xml object.

I’m aware that this is by no means a good implementation, but it works for me and there will probably be a fix in the original cakephp helper at some point. But if you run into the same problems as I did, feel free to try this solution and also to improve it! You can also just comment if you have troubles running it.

published on Feb 8, 2012 12:00 AM

Read more

Cakephp application + Netbeans + Remote Access + SSH

Cakephp application + Netbeans + Remote Access + SSH

How to configure Netbeans so it accesses your remote cake application and updates changes on run/on save

Just in case someone is searching for a working way of configuring remote server in Netbeans to work with cake application, here goes good tutorial:

http://www.thewebshop.ca/blog/2009/07/working-with-remote-files-in-netbeans/

Good luck!

published on Feb 8, 2012 12:00 AM

Read more

CakePHP 2.0.6 released

CakePHP 2.0.6 released

This will hopefully be the last 2.0 release, the CakePHP will focus on getting 2.1 done and all bugfixes and security patches will go into this branch.

The CakePHP core team is proud to announce the immediate availability of CakePHP 2.0.6 [1]. This will hopefully be the last minor version released for the 2.0 branch if no important changes are needed to be done before we get version 2.1 stable. After this one all bugfixes and security patches will be done in the 2.1 branch, which is 100% compatible with this one.

In total, there were over 90 commits and 45 issues have been resolved since 2.0.5. A complete list of the changes can be viewed on the changelogs page [2], but a quick summary of changes that made it into 2.0.6:

  • Updating minimum PHP version requirement to 5.2.8 due to PHP bugs #44251 and #45748
  • Model does not call calculate() and expression() method on the datasource if it does not implements it.
  • SqlServer views can be mapped with models as you can do with normal tables.
  • Fixed issue where session would always be regenerated regardeless of configs set.
  • Not requiring a database connection for Models having $useTable = false when combined with the FormHelper
  • Not throwing errors when instantiating model classes with no constructor using the ClassRegistry
  • Fixing memory leaks in some Database drivers
  • TextHelper::excerpt() now works as documented.
  • Defaulting back to using PHP_SELF to get current url, this solves several issues in shared hosts

We are almost done with the 2.1 release and you can expect a stable release within a couple of weeks. 2.1 will be fully backwards compatible with 2.0, and add a number of useful features. For a list of what is complete, and what is planned for 2.1, see the roadmap [3] and the in-progress 2.1 migration guide [4]

Thanks once again to the excellent CakePHP community, for all of the outstanding work. Without your contributions and love there would be no CakePHP.

  • Download 2.0.6 [1] View the changelog [2]

Links

published on Feb 6, 2012 12:00 AM

Read more

HTML 5 Multiple File Upload With Cake

HTML 5 Multiple File Upload With Cake

A quick tutorial on how to use HTML5’s multiple file upload with CakePHP

With HTML5 comes the ability to select multiple files using a regular file input field.

It took me a little while to work out how to do this so I thought I’d post it here.

To start with we are trying to get html similar to this using the cake input helper.

<input name='uploads[]' type=file multiple>

To achieve this we need to use the Form helper as so:

<?php
echo $this->Form->create('Model', array('type' => 'file'));
echo $this->Form->input('files.', array('type' => 'file', 'multiple'));
echo $this->Form->end('Upload');
?>

From the controller inspecting the $this->data property will give us something like this:

Array
(
    [Model] => Array
        (
            [files] => Array
                (
                    [0] => Array
                        (
                            [name] => 20120112_153642.jpg
                            [type] => image/jpeg
                            [tmp_name] => E:\wamp\tmp\phpD71.tmp
                            [error] => 0
                            [size] => 1922765
                        )
                    [1] => Array
                        (
                            [name] => 20120112_153845.jpg
                            [type] => image/jpeg
                            [tmp_name] => E:\wamp\tmp\phpD81.tmp
                            [error] => 0
                            [size] => 1122957
                        )
        )
)

You can then loop through the files array and process them as usual.

published on Jan 31, 2012 12:00 AM

Read more

Running CakePHP using the Facebook's HipHop compiler

Running CakePHP using the Facebook’s HipHop compiler

I always had the curiosity of trying to compile CakePHP to C++ code, but never had the time. This year I decided to give it a go...

Facebook surprised the PHP community in early 2010 when announced they managed to write a compiler for PHP to produce C++ (http://developers.facebook.com/blog/post/358) code. Being PHP the most popular language for web applications, it faces a lot of competition from other languages to position themselves as the fastest language out there, buy this announcement was a real game changer as it is hard to argue against the speed of compiled machine code.

It was clear, though, that using the HipHop compiler was not for everyone. It is widely known you can very easily scale PHP for high performance applications, frameworks usually provide tools to squeeze speed and foster cache use to make your application faster, and throwing more hardware and the problems is often the cheapest and most rapid way of serving your code to more users. Nevertheless, having an almost free way of making your code twice as fast under the same hardware sounds too good to not give it a try.

echo "<?php echo 'Hello World'; ?>" > test.php
src/hphpi/hphpi test.php

1 My Main motivation to try compiling CakePHP with Facebook’s HipHop was simple curiosity: will it work? I though it was worth the shot. By the time I was having 2the idea, there were a lot of discussions in the forums and twitter about which the fastest PHP framework was, there were tons of benchmarks out there with lot of bias, and most of them portrayed CakePHP as a slow beast that only a fool would use.

Even though that was an outright lie, I thought the discussion would be over and basically turned irrelevant if one could compile the code and get awesome speed without having to change the code. So I embarked in a surprisingly simple adventure for converting CakePHP into C++ code.

Requirements

To perform my testing I used a Ubuntu 11.10 64bits virtual machine, if you are building it in your own box, or using a virtual machine, make user it is 64bits, as that is the only platform HipHop runs in. Additionally you will need:

public $default = array(
    'datasource' => 'HipHop.Database/HpMysql',
    'persistent' => false,
    'host' => 'localhost',
    'login' => 'root',
    'password' => 'root',
    'database' => 'cakephp',
    'prefix' => '',
    'encoding' => 'utf8',
);

2

Installation

Follow the installing instructions in this page Building and Installing on Ubuntu 11.10 (https://github.com/facebook/hiphop-php/wiki/Building-and-Installing-on-Ubuntu-11.10) do not skip any part, all libraries listed there and patches to be applied are required. There are a couple of problematic steps in the aforementioned guide when building required libs. I have created some repos in github, including a fork of HipHop itself so you can clone them and just build the sources without having to redo the work I did. These are my forks:

You can download and compile libevent without applying any custom patches. Follow the installation guide and use my forks where it tells you to download from the original source.

Once HipHop is compiled, create a simple php file and test whether it works fine. Make sure you read this guide (https://github.com/facebook/hiphop-php/wiki/Running-HipHop) before you attempt to do anything, it is crucial that you set up the environment variables HPHP_HOME and HPHP_LIB as shown in that link.

Testing your build

cd hiphop-php
export CMAKE_PREFIX_PATH=`/bin/pwd`/../
export HPHP_HOME=`/bin/pwd`
export HPHP_LIB=`/bin/pwd`/bin

I used the interpreter instead of compiling directly. This is what I did: B0x1A1 You can follow the more advanced examples for compiling your code explained at the wiki page. I would strongly recommend you feel comfortable with compiling simple examples and getting them running before proceeding with compiling CakePHP.

Compiling CakePHP

The most important part of compiling your application is getting ready for it. I used a simple blog baked from a rather simple database schema to perform my testing using CakePHP 2.1-beta, and I made an exhaustive testing of every feature using the hphpi interpreter first.

Remember that HipHop produces a single program out of every php source file your application uses. So the simplest way of compiling and testing your source is by keeping the default CakePHP folder structure (where app and lib lives under the same root folder). There are a few simple modifications we have to do in order to test the application using the interpreter.

Installing the HipHop plugin

First step is installing my HipHop plugin (https://github.com/lorenzo/HipHop), just drop it in app/Plugin and enable it using CakePlugin::load(‘HipHop’) in your app/Config/bootstrap.php file. This plugin contains several useful scripts to adapt your application for the new environment.

Keep in my that HipHop only supports Mysql and SQLite as databases for your project, but unfortunately, the PDO implementation Facebook did does not behave exactly the same as the original PHP implementation. For that reason the plugin bundles a somewhat modified Mysql source that you need to use if you expect your application to work correctly when compiled. This is a database.php example: B0x1A2

Generating the class map

HipHop does not implement any kind of automatic class loader, so we need to provide a complete list of classes to be used in your application, this is a big difference between the hphpi interpreter and the compiler. Your CakePHP application will run just fin in the interpreter, but it won’t after compiling if you are unable to tell it where your classes are. For this purpose, the plugin bundles a shell that needs to be executed before compiling your code:

app/Console/cake HipHop.ClassPath

The previous command will generate a file under app/Config named incules.php containing hard-coded include statements for all your files containing classes. It is extremely importart you have only 1 class per file, also avoid having files combining class definitions and procedural code.

Next step is to copy the file from app/Plugin/HipHop/Config/webroot/index.php to app/webroot/index.php

cp `app/Plugin/HipHop/Config/webroot/index.php app/webroot/index.php

Main difference between both files is that the one provided by the plugin includes the class map before dispatching the request. This enables the compiler to know beforehand where to find any needed class.

Test driving it

Copy the app/Plugin/HipHop/Config/config.hdf file in your application root folder, and edit it. Your will find comments inside the file of how it should look like, this is one example:

Server {
    Port = 80
    SourceRoot = /home/lorenzo/cakephp
}

VirtualHost {
    * {
        Prefix = hiphop.local
        RewriteRules {
            * {
                pattern =    ^(.*)$
                to = /app/webroot/index.php$1
                qsa = true
                    conditions {
                            * {
                                pattern = ^/(css|js|img)/*
                                negate = true
                            }
                    }
            }
            * {
                pattern = ^/(css|js|img)/(.*)$
                to = /app/webroot/$1/$2
                qsa = true
            }
        }
    }
}

Run the interpreter in server mode for the first time using your application source. Go to the root folder containing your app directory and execute the following command:

sudo ~/dev/hiphop-php/src/hphpi/hphpi -m server -c config.hdf

Change directories accordingly if you did not follow the guide and setup the folders as suggested. After running this command you will be able to access http://localhost/ and start browsing your application, you can also provide the -p option to select a different port like 8080 if you don’t want to run the interpreter as super user.

When you have tested every feature in your app, and feel comfortable with results, it is time to start compiling your source.

Compiling your application

When compiling your source expect a lot bumps in the road. Hopefully you won’t have different problems that I had, so the plugin is already bundling a solution for those. Compiling the source requires a full list of files to include in the resulting binary, as always use the plugin to produce it:

app/Plugin/HipHop/Config/scripts/generate_list

Previous command will create the files.list file. Right after generating the list, use the following command to compile your application:

~/dev/hiphop-php/src/hphp/hphp --input-list=files.list -k 1 --log=3 -v "AllDynamic=true"

Expect it to fail. It will complain about missing PDO constants. Let’s take care of it with the following command:

app/Plugin/HipHop/Config/scripts/fixconstants

It will run a search and replace function inside /tmp/hphp* (there should be only one directory matching the expression) fixing any incorrectly exported symbol. Now cd to the build folder and start the process again:

cd /tmp/hphp* && make

Be patient, it will take some time. Hopefully the compiling process will finish without errors, and it will produce a binary file named program, be ready to execute it for the first time.

Copy the program executable anywhere you like, I put it again into my application root folder. Run it for the first time:

./program -m server -v “Server.DefaultDocument=index.php” -c config.hdf

Browse your application again and make sure everything runs as it should, and be amazed at the speed and how much concurrent connections it can handle at the same time.

Conclusion

Running CakePHP using HipHop is arguably simple one you automate the process, I’m still far from it, but I have created script for most steps. I’m really looking forward trying the new HipHop branch featuring a new virtual machine and a just in time compiler.

I’m pretty confident there are no hidden bugs when running CakePHP using HipHop, but I can be very wrong on this one. Want to help me find those bugs and fixing them? Will you compile your own applications? Leave your thoughts in the comments section!

published on Jan 30, 2012 12:00 AM

Read more

Datetime formatter behavior

Datetime formatter behavior

Taking the idea from previous post, I have made a Behavior that formats date and datetime fields.

I took the idea from Rikkin post:http://bakery.cakephp.org/articles/rikkin/2012/01/26/formatos_de_fechas

Give thanks to him, I only put his idea into a behavior.

Here’s the code: (pasted here: http://bin.cakephp.org/saved/72238)

<?php

class DatetimeFormatterBehavior extends ModelBehavior {

    private $__defaultSettings = array(
        'date_format' => '%d/%m/%Y',
        'date_suffix' => '_d',
        'datetime_suffix' => '_dt',
        'datetime_format' => '%d/%m/%Y %H:%i:%s',
        'fields' => true,
    );

    function setup(&$model, $config = array()) {
        $this->settings[$model->alias] = $config + $this->__defaultSettings;
        $this->addDefaultVirtualFields($model);
    }

    function addDefaultVirtualFields($model) {
        extract($this->settings[$model->alias], EXTR_SKIP);
        $colTypes = $model->getColumnTypes();
        foreach($colTypes as $field => $type){
            if($fields === true || in_array($field, $fields)){
                if($type === 'date' || $type === 'datetime'){
                    $model->virtualFields[$field . $date_suffix] = "date_format($model->alias.$field, '" . $date_format . "')";
                    $model->virtualFields[$field . $datetime_suffix] = "date_format($model->alias.$field, '" . $datetime_format . "')";
                }
            }
        }
    }

}

// Usage:
class User extends AppModel {

    var $actsAs = array('DatetimeFormatter');

}

// Test (take a look to output):
debug($this->User->find('first'));

published on Jan 30, 2012 12:00 AM

Read more

960 Fluid Grid System Bake Templates CakePHP 2.1

960 Fluid Grid System Bake Templates CakePHP 2.1

I found this project and made some changes to it and published it on Github. All the credits go to the original poster (Tom_M http://bakery.cakephp.org/users/view/tom_m), all I did was make it available on Github and a few changes for CakePHP 2.1. You can get the ‘new’ version at https://github.com/snelweg/CakePHP-960-fluid

Want to use 960 grid system in your baked app? Ever see this “fluid” template that uses it? http://www.designinfluences.com/fluid960gs - I put it into some bake templates. It’s not that I don’t like the default baked views, but I wanted something more generic and flexible. This template is extremely fast to work with too. You can add more boxes and other content very easily as opposed to the default bake templates.

If you are unfamiliar with the 960 Fluid Grid System template created by Stephen Bau, then check out the link in the intro. It’s a very clean and basic gray/black/white layout with some nice collapsible divs and accordions and such. The page even says, “templates for rapid interactive prototyping.” Sounds like a perfect match for a rapid framework like CakePHP.

You can download the file from my server: http://www.shift8creative.com/files/960-fluid-cakephp-bake-template.tar.gz

Not to take you away from the Bakery or anything, but if you were so inclined, you can see some screenshots on my site: http://www.shift8creative.com/project/960-fluid-grid-system-cakephp-bake-templates

How do you use it? Look at the README in the zip file, but basically you’ll want to copy/merge the files in the same structure to your app. Then when you go to bake your view templates you should have a numbered option with “default” and “960grid” to choose from. Maybe others too if you have more bake templates. Anyway, choose “960grid” and that’s it. You should be set.

Check out the manual for more information: http://book.cakephp.org/view/789/Modify-default-HTML-produced-by-baked-templates

New version

You can get the ‘new’ version at https://github.com/snelweg/CakePHP-960-fluid

published on Jan 30, 2012 12:00 AM

Read more

Emogrifier Plugin for rendering HTML formatted email

Emogrifier Plugin for rendering HTML formatted email

CakephpEmogrifierPlugin is a CakePHP 2.0x Plugin that makes of using Emogrify on your HTML output easy.

Wondering what Emogrify is? Emogrifier is a great library from Pelago that deals with much of the hassle involved with HTML formatted email messages:-

This Plugin is a wrapper around Emogrifier making it easy to use in CakePHP 2.0x

Step 1

Download the Plugin here:-https://github.com/ndejong/CakephpEmogrifierPlugin

Step 2

Copy or symlink CakephpEmogrifierPlugin into a path named Emogrifier in your Plugin path like this:-

app/Plugin/Emogrifier

Take careful note of the Plugin pathname, the name is “Emogrifier”, not EmogrifierPlugin or CakephpEmogrifierPlugin, it’s just Emogrifier. I spell this out because it’s an easy thing to trip up on especially if your pulling this down from github or unpacking from a tarball.

Step 3

Be sure to load the plugin in your bootstrap.php or core.php, like this:-

CakePlugin::load('Emogrifier');

Step 4

Tell your controller to render your view with Emogrifier like this:-

$this->viewClass = 'Emogrifier.Emogrifier';

Questions and Answers

Q: Pelago’s Emogrifier class requires you to pass in the CSS but this plugin does not, what’s going on? A: We parse the HTML from the View->output attribute looking for CSS from link and style elements then stich the whole thing together - it makes using this a little easier.

Q: I’m using Emogrifier before rendering to webpages and I can’t see any difference A: Take a look at the HTML source, you should notice that all your CSS styles are now inline element style attributes.

Q: Why does this Plugin have no Tests? A: Because call me daft, I just can’t work out how to write a PHPUnit test for output from a Plugin View - let me know if you do!

published on Jan 29, 2012 12:00 AM

Read more

Attach Plugin

Attach Plugin

Attach Plugin, is easy upload in CakePHP 2. For several projects I have used the MeioUpload plugin and he was really good for me, but for some new projects I`d like to use polymorphic model for mine attachments, and the new and good Imagine library for generate thumbs, and manipulate images. So I decided to start one plugin, that is called Attach. To use it’s really simple:

Installation

Usage

In a model that needs uploading, replace the class declaration with something similar to the following:

It’s important to remember that your model class can have your own fields, and it will have a extra relation with Attachment model with the fields that are upload.

App::uses('AppModel', 'Model');

class Media extends AppModel {

    public $validate = array(
        'image' => array(
            'extension' => array(
                'rule' => array(
                    'extension', array(
                        'jpg',
                        'jpeg',
                        'bmp',
                        'gif',
                        'png',
                        'jpg'
                    )
                ),
                'message' => 'File extension is not supported',
                'on' => 'create'
            ),
            'mime' => array(
                'rule' => array('mime', array(
                    'image/jpeg',
                    'image/pjpeg',
                    'image/bmp',
                    'image/x-ms-bmp',
                    'image/gif',
                    'image/png'
                )),
                'on' => 'create'
            ),
            'size' => array(
                'rule' => array('size', 2097152),
                'on' => 'create'
            )
        ),
        'swf' => array(
            'extension' => array(
                'rule' => array(
                    'extension', array(
                        'swf',
                    )
                ),
                'message' => 'File extension is not supported',
                'on' => 'create'
            ),
            'mime' => array(
                'rule' => array('mime', array(
                    'application/x-shockwave-flash',
                )),
                'on' => 'create'
            ),
            'size' => array(
                'rule' => array('size', 53687091200),
                'on' => 'create'
            )
        ),
        'zip' => array(
            'extension' => array(
                'rule' => array(
                    'extension', array(
                        'zip',
                    )
                ),
                'message' => 'File extension is not supported',
                'on' => 'create'
            ),
            'mime' => array(
                'rule' => array('mime', array(
                    'application/zip',
                    'multipart/x-zip'
                )),
                'on' => 'create'
            ),
            'size' => array(
                'rule' => array('size', 53687091200),
                'on' => 'create'
            )
        ),
    );

    public $actsAs = array(
        'Attach.Upload' => array(
            'swf' => array(
                'dir' => 'webroot{DS}uploads{DS}media{DS}swf'
            ),
            'image' => array(
                'dir' => 'webroot{DS}uploads{DS}media{DS}image',
                'thumbs' => array(
                    'thumb' => array(
                        'w' => 190,
                        'h' => 158,
                        'crop' => true,
                    ),
                ),
            ),
            'zip' => array(
                'dir' => 'webroot{DS}uploads{DS}media{DS}zip'
            ),
        ),
    );

You also need to specify the fields in your database like so

CREATE TABLE  `attachments` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `filename` varchar(150) NOT NULL,
  `model` varchar(150) NOT NULL,
  `foreign_key` int(11) NOT NULL,
  `type` varchar(100) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

Create your upload view, make sure it’s a multipart/form-data form, and the filename field is of type ‘file’:

echo $this->Form->create('Media', array('type' => 'file'));
echo $this->Form->input('name');
echo $this->Form->input('image', array('type' => 'file'));
echo $this->Form->input('swf', array('type' => 'file'));
echo $this->Form->input('zip', array('type' => 'file'));
echo $this->Form->input('status');
echo $this->Form->end(__('Submit'));

Attach creates automatic for you the relationship with the model Attachment, for each type that you define:

var_dump($this->Media->AttachmentImage);
var_dump($this->Media->AttachmentSwf);
var_dump($this->Media->AttachmentZip);

It will be always “Attachment” plus the type! So that’s it the Attach plugin will handle your files, you can keep uptodate with the changes at the plugin at github: https://github.com/krolow/Attach

published on Jan 27, 2012 12:00 AM

Read more

Dateformatter

Dateformatter

Hi!, Im new on the bakery, this is my first article, I hope this will be helpfull. This is a behaviors for dateformat, I was looking for something like this, but I never could get one that indulge my needs. so, here it goes. A simple Dateformat behaviors. (lo publique en español tambien)

<?php class DateformatBehavior extends ModelBehavior {

//Our  format
var $dateFormat = 'd.m.Y';
//datebase Format
var $databaseFormat = 'Y-m-d';

function setup(&$model) {
    $this->model = $model;
}

function _changeDateFormat($date = null,$dateFormat){
    return date($dateFormat, strtotime($date));
}

//This function search an array to get a date or datetime field.
function _changeDate($queryDataConditions , $dateFormat){
    foreach($queryDataConditions as $key => $value){
        if(is_array($value)){
            $queryDataConditions[$key] = $this->_changeDate($value,$dateFormat);
        } else {
            $columns = $this->model->getColumnTypes();
            //sacamos las columnas que no queremos
            foreach($columns as $column => $type){
                if(($type != 'date') && ($type != 'datetime')) unset($columns[$column]);
            }
            //we look for date or datetime fields on database model
            foreach($columns as $column => $type){
                if(strstr($key,$column)){
                    if($type == 'datetime') $queryDataConditions[$key] = $this->_changeDateFormat($value,$dateFormat.' H:i:s ');
                    if($type == 'date') $queryDataConditions[$key] = $this->_changeDateFormat($value,$dateFormat);
                }
            }

        }
    }
    return $queryDataConditions;
}

function beforeFind($model, $queryData){
    $queryData['conditions'] = $this->_changeDate($queryData['conditions'] , $this->databaseFormat);
    return $queryData;
}

function afterFind(&$model, $results){
    $results = $this->_changeDate($results, $this->dateFormat);
    return $results;
}

function beforeSave($model) {
    $model->data = $this->_changeDate($model->data, $this->databaseFormat);
    return true;
}

} ?>

published on Jan 26, 2012 12:00 AM

Read more

CakePHP 2.1 beta Hot and fresh

CakePHP 2.1 beta Hot and fresh

Following the release of 2.1.0-alpha two weeks ago, the CakePHP core team is excited to annonce the immediate availability of 2.1.0-beta.

The CakePHP core team is proud to announce the immediate availability of CakePHP 2.1.0 beta [1]. As noted in previous release, this version is fully backwards compatible with 2.0.5, making it a breeze to update your apps to start taking advantage of the many improvements that made into this release.

In total, there were over 100 commits and 5 new features or enhancements added to this beta version, in addition to the initial 2.1 alpha release. A complete list of the changes can be viewed in the changelogs page [2]. This is a quick list of this version’s main highlights:

ThemeView is now deprecated

We realized that having to use a separate class and add more configuration to the controller class was not the ideal solution. We’ve merged all the ThemeView functionality into the View class. Easier theme support!

Improved HTTP caching

One of the major differences between 2.0 and 1.3 is the response class with which you can set response headers more easily. This change has helped a lot people who set cache headers to take advantage of reverse proxies such as Varnish. We have taken this one step further and provided several new methods in CakeResponse class to fine-tune options for HTTP caching.

RequestHandlerComponent will now stop the view rendering process if it detects the client has a cached version of the resource. This means reduced response times, and less CPU cycles per request. In order to take advantage of this you need to use the modified() or etag() methods provided in the CakeResponse class. The CakePHP book has some examples to help you understand this new feature.

Miscellaneous Changes

  • Transaction commands (BEGIN, COMMIT, ROLLBACK) are now shown in database log
  • Added Set::nest() and Set::get(). The former is used to created a nested array out of a plain one using an array key as reference. Set::get() is used to access any array value using dot notation.
  • Added Router::defaultRouteClass() to get/set the default Route class. This makes it easy to set a global default, useful for slug routes or i18n.
  • I18n::translate() now accepts a new $language param. It also now exposes methods to read .po files, useful for custom translation interfaces.`
  • Authenticate objects can now receive a ‘recursive’ option to limit data returned in queries used for finding users.

We have decided to keep a single book for the whole 2.x branch. You can read changes related to the 2.1 version in the current book. We are working towards having a new api site for this new version as soon as possible. As always, thanks to the friendly CakePHP community for the patches, documentation changes and new tickets. Without you there would be no CakePHP!

  • Download a packaged release [1]
  • View the changelog [2]

Links

published on Jan 23, 2012 12:00 AM

Read more

NiceAuth - User Management Plugin with OpenID

NiceAuth - User Management Plugin with OpenID

NiceAuth is a user management and authorization plugin that uses CakePHP’s Acl Component to manage users and permissions via a database. This plugin allows for permissions per controller or action for users and/or groups.

Features

  • ACL Database - Allows you to control access to controllers and actions for each user or group
  • User Registration - Easy to use form for user signup
  • OpenID - Allows users to signup with a single click using their OpenID account (eg. Google, Yahoo, etc.)
  • Password Reset Function - Users can enter there email address and a temporary password will be sent to them
  • Installation Script - Database tables are created and filled by using a CakePHP script in one easy step
  • Admin Dashboard - Allows for easy user management, group creation and permissions settings

Demo available at: http://niceauth.rsmartin.me

For more information and downloads: https://github.com/rsmartin/NiceAuth

published on Jan 22, 2012 12:00 AM

Read more

Mozilla BrowserID authentication plugin

Mozilla BrowserID authentication plugin

I just stumbled on Mozilla’s new OpenID competitor (http://browserid.org ) and liked it. I figured I would be albe to implement it on my currently existing user database without any changes, so I started a simple cake plugin for it. The result is a simple way to enable your users to login to your cake application using only their email address.

Please let me know what you think of my first plugin. Github page is http://github.com/OverFlow636/ofbid

Prerequisites

  1. Your application should already have an authentication method setup, this plugin is simply designed to augment it.
  2. Your AppController needs to use the Auth and Session components
  3. Your server needs to support curl and ssl

To Install B0x1A0

  1. Clone ` https://github.com/OverFlow636/Ofbid.git ` into /Plugin/Ofbid
  2. Load the plugin in your bootstrap.php with the bootstrap option true ex. CakePlugin::load(array(‘Ofbid’=>array(‘bootstrap’=>true)));
  3. In your AppController or in the controller you would like to use the button add the following helper Ofbid.Ofbid
  4. In the login view call $this->Ofbid->loginButton() to print the BrowserID login button

Configuration B0x1A0

  • Default settings will work for many applications, but there are many options to customize if you require
  • All session redirect messages
  • All redirect locations
  • Optional CakeEventListener can be configured to perform user login logic, without having to change plugin code
  • To configure any of theese options checkout the plugins bootstrap.php for the Configure keys, and write them in your applications config

published on Jan 22, 2012 12:00 AM

Read more

Notice!

Adding multilingualism to single language site without i18n and/or TranslateBehaviour ==================

I’m currently working on a site that requires multiple languages. As I didn’t know this at the start of the project, I didn’t prepare to use CakePHP integrated facilities for translation. So I decided to put a little something of my own...

Notice!

This tutorial is for CakePHP 2.x!

Basic premises

In CakePHP you have wonderful things like i18n and l10n, and TranslateBehaviour. Problem is this is only useful if you design your app from the beginning to do the translation as you go on. This presumes having separate tables for translated content and so on. But what if you want to use your contents table for all language content, your news table for all the news in all the languages and so on. Then, what you do is just add language_id to all the tables from where you pull content, and have a languages table for mapping your languages to names, and of course for adding new languages.

DB/Model setup

First you should create your content table, containing a language_id field. And of course the languages table. Like so: ` CREATETABLE`contents`( id`int(11)NOTNULLAUTO_INCREMENT, `title`varchar(50)DEFAULTNULL, `body`varchar(250)DEFAULTNULL, `language_id`int(11)DEFAULTNULL, PRIMARYKEY(`id) )ENGINE=MyISAMDEFAULTCHARSET=utf8AUTO_INCREMENT=1;

CREATETABLE`languages`( id`int(11)NOTNULLAUTO_INCREMENT, `value`varchar(20)NOTNULL, PRIMARYKEY(`id), UNIQUEKEY`value`(value) )ENGINE=MyISAMAUTO_INCREMENT=5DEFAULTCHARSET=utf8AUTO_INCREMENT=5; ` Create a model and the associations like. Content > belongsTo > Language / Language > hasMany > Content. Example below.

Content.php

` classContentextendsAppModel{

public$displayField=’title’; public$validate=array( ‘title’=>array( ‘notempty’=>array( ‘rule’=>array(‘notempty’), ), ), ‘body’=>array( ‘notempty’=>array( ‘rule’=>array(‘notempty’), ), ), );

public$belongsTo=array( ‘Language’=>array( ‘className’=>’Language’, ‘foreignKey’=>’language_id’, ‘conditions’=>’‘, ‘fields’=>’‘, ‘order’=>’’ ) ); } `

Language.php

` classLanguageextendsAppModel{

public$displayField=’value’;

public$hasMany=array( ‘Content’=>array( ‘className’=>’Content’, ‘foreignKey’=>’language_id’, ‘dependent’=>false) );

} <code> <p>Wellthattakescareofdb/modelpart,letsgoontoController.</p>

<h2>Controllersetup</h2>

<p>Thecontrollersetupisprettyeasy,butdependsonhowisyoursiteconfigured. IdoallmyfrontendcontentfromPagesControllercoupledwithextensiveuseofele ments,andofcourseroutingtovariousactionsdefined.ForeaseofuseI’llbaseth isonthebasicPagesControlleryougetwhenyoudownload/unpackCakePHP.ButI’mg ettingaheadofmyself.Thereisonethingyoumustconfigurebeforeyoudoanything .YoumustconfigureyourapptouseSessioncomponent.Thisisparamountasthisall isbasedonaverysimpletrickusingsessions:)

So,let’sgo...InAppControlleryousimplyaddthefollowingcode

<code> <?php classAppControllerextendsController{ public$components=array(‘Session’); } ` That’s it, yes. Only that, a bit more code is contained in the controller that serves the front page where you put the selectors for the language. Basically links to controller actions only. I put the links in default.ctp layout file because the top menu is the same for all the pages. So let’s look at how to config PagesController to make the language switching possible. ` <?php classPagesControllerextendsAppController{ publicfunctiondisplay(){ $path=func_get_args(); $count=count($path); if(!$count){ $this->redirect(‘/’); } $page=$subpage=$title_for_layout=null;

if(!empty($path[0])){ $page=$path[0]; } if(!empty($path[1])){ $subpage=$path[1]; } if(!empty($path[$count-1])){ $title_for_layout=Inflector::humanize($path[$count-1]); } $this->set(compact(‘page’,’subpage’,’title_for_layout’)); $this->render(implode(‘/’,$path)); } publicfunctionsetLangEng(){ $this->Session->write(‘lang’,‘2’); $this->redirect(array(‘controller’=>’pages’,’action’=>’display’,’home’ )); } publicfunctionsetLangGer(){ $this->Session->write(‘lang’,‘1’); $this->redirect(array(‘controller’=>’pages’,’action’=>’display’,’home’ )); } } ` The only custom code here is setLangEng() and setLangGer() method that only write a session variable for the language used. And of course you have to configure the routes for those actions to map correctly. That goes in your routes.php, and goes something like this. ` //restoftheroutes.phpyouleavealone,justaddthesetwolinesafter //Router::connect(‘/eng’,array(‘controller’=>’pages’,’action’=>’displa y’,’home’));

Router::connect(‘/eng’,array(‘controller’=>’pages’,’action’=>’setLangE ng’)); Router::connect(‘/ger’,array(‘controller’=>’pages’,’action’=>’setLangG er’)); ` And the last, but not the least piece of magic happens in ContentsController where you set the content to get for each language based on language_id (‘lang’ session variable) you set in the PagesController.php. So you open the ContentsController.php, and add a few methods of your own, like so... ` <?php classContentsControllerextendsAppController{ //basicindex,add,view,edit... publicfunctiongetcont(){ if($this->Session->read(‘lang’)==1) { $this->paginate=array( ‘conditions’=>array(‘Content.language_id’=>1), ‘limit’=>3, ‘fields’=>array(‘News.body’) ); $content=$this->paginate(‘Content’); return$content; } if($this->Session->read(‘lang’)==2) { $this->paginate=array( ‘conditions’=>array(‘Content.language_id’=>2), ‘limit’=>3, ‘fields’=>array(‘News.body’) ); $content=$this->paginate(‘Content’); return$content; } } `

Finishing it up

All you have to do now is to setup links for the language selection, and of course, get the content. I do so in elements. But first the links... Open your /app/View/Layouts/default.ctp and put the following in in the place you want the language selection menu to be. ` <ahref=”/ger”>Ger</a> <ahref=”/eng”>Eng</a> ` As you see i used plain HTML links, but that is because I like it more that way, because the designer that works on the front end can then find their way around more easily.

The last thing is to call up the content in the view. Because of the way it is set up it will be the same view for every language, just the content (or whatever you set up this way) will change depending on the session variable ‘lang’. So the view would look something like this (I’ll use the requestAction because I’m calling it from a different controller). ` //restofyourviewcode <divclass=”content-boxsix-cols”> <?php$contents=$this->requestAction(‘/contents/getcont’);?> <?phpforeach($contentsas$content):?> <h2><?phpecho$content[‘Content’][‘title’];?></h2> <p><?phpecho$content[‘Content’][‘body’];?></p> <?phpendforeach;?> </div> ` So, this is about it... This is my first CakePHP writeup, all before were, how do I do this, or how do I do that. All the other solutions I’ve come accross for adding multiple languages had meant I had to do massive refactoring, so I settled for this solution. It works just fine. So if you like it, shout :)

published on Jan 22, 2012 12:00 AM

Read more

Mpdf component for generating PDF files from HTML

Mpdf component for generating PDF files from HTML

Mpdf consists only from one component class that uses mPDF class (located in vendors) to generate PDF file instead of standard output.

mPDF is a great class that can create PDF files from HTML. For more information see mPDF homepage.

I wrote this component to easily use mPDF with cake views. You just need to initialize Mpdf component, set desired layout (view) and instead of standard output the PDF file will be generated.

Short example in controller: ` public$components=array(‘Mpdf.Mpdf’);

publicfunctiontestpdf(){ $this->Mpdf->init(); $this->Mpdf->setFilename(‘file.pdf’); $this->Mpdf->setOutput(‘D’); //cancallanymPDFmethodvia$this->Mpdf->pdf $this->Mpdf->pdf->SetWatermarkText(“Draft”); } ` Download the code from https://github.com/segy/Mpdf

published on Jan 19, 2012 12:00 AM

Read more

Cakephp V2 without a database (Fixed)

Cakephp V2 without a database (Fixed)

This bug has now been fixed https://github.com/cakephp/cakephp/commit/ 6aa08b5f52955d15fb7e44ed28efcd8156c958d2

A very simple explanation on how to get around the topical bug in CakePHP V2 and use it without a database.

When you want to use CakePHP without a database create the file /app/Model/Datasource/DummySource.php with the following content

class DummySource extends DataSource {

    function connect() {
        $this->connected = true;
        return $this->connected;
    }

    function disconnect() {
        $this->connected = false;
        return !$this->connected;
    }

    function isConnected() {

        return true;
    }

}

Next update your /app/Config/database.php file altering the ‘default’ array to include a datasource that reads

'datasource' => 'DummySource'

Don’t forget, for every model you create include the property

$useTable = false

That’s all folks.

published on Jan 19, 2012 12:00 AM

Read more

SOPA Blackout component

SOPA Blackout component

On the Tuesday 24th January 2012, the US Senate will vote on the internet censorship bill. Whilst it is an American law, it has far reaching repurcusions for the web as a whole. Sites such as Reddit have said that on January 18th they are going to go dark between 8am and 8pm. This component will let you join the cause. On 18th January your site will display a customisable page. Search engine rankings will not be affected as the plugin sends a 503 status.

On the Tuesday 24th January 2012, the US Senate will vote on the internet censorship bill.

Whilst it is an American law, it has far reaching repurcusions for the web as a whole. Sites such as Reddit have said that on January 18th they are going to go dark between 8am and 8pm.

This component will let you join the cause. On 18th January your site will display a customisable page.

Search engine rankings will not be affected as the plugin sends a 503 status.

It’s not very ‘Cake-y’ - I tried using plugin first, then thought about an error page with the component, but I wanted just one file people could download and then use if they wished.

Suggestions welcomed...

<?php
    class SopaBlackoutComponent extends Object {


        var $sopa_blackout_page_title = 'Supporting anti-SOPA Blackout day'; // title and h1 content
        var $sopa_blackout_include_video = true; // embed the video from americancensorship.org on your site?
        var $sopa_blackout_include_form = true; // include the form from americancensorship.org on your site?
        var $sopa_blackout_message = '<p>On the Tuesday 24th January 2012, the US Senate will vote on the <a href="http://en.wikipedia.org/wiki/Stop_Online_Piracy_Act" target="_blank">internet censorship bill</a>.<br /><br />Whilst it is an American law, it has far reaching repurcusions for the web as a whole.<br /><br />There are many companies against SOPA, such as <a href="http://www.mattcutts.com/blog/internet-censorship-sopa/" target="_blank">Google</a>, <a href="http://blog.reddit.com/2012/01/stopped-they-must-be-on-this-all.html" target="_blank">Reddit</a>, <a href="http://news.cnet.com/8301-31921_3-57342914-281/silicon-valley-execs-blast-sopa-in-open-letter/" target="_blank">Facebook, Twitter, Wikipedia</a>, and today I am lending my weight to the argument by taking my site down for the day.<br /><br />If you think SOPA doesn\'t affect you, please think again. Watch the video below, or use the form below to force politicians to take notice.<br /><br />Thank you</p>';
        var $sopa_blackout_date = '2012-01-18'; // SOPA Blackout Day - 18th January 2012
        var $sopa_blackout_timestart = 8; // Starting at 8am or 08:00:00
        var $sopa_blackout_timeend    = 20; // Ending at 8pm or 20:00:00
        var $sopa_blackout_timezone    = null; // recommended timezones would be America/New_York or America/Los_Angeles


        //called before Controller::beforeFilter()
        function initialize(&$controller, $settings = array()) {
            // saving the controller reference for later use
            $this->controller =& $controller;
        }


        //called after Controller::beforeRender()
        function beforeRender(&$controller) {
            if($this->sopablackout_checkdate()){
            $message = '<!DOCTYPE html>
    <html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
        <title>'.$this->sopa_blackout_page_title.'</title>
        <style>
            body, html {background-color:#000000; color:#ffffff;font-family:"Trebuchet MS", Myriad, Arial;}
            div.sopablackout_padding {padding:24px;}
            #container {width:1000px; margin:40px auto;}
            p, div.sopablackout_padding { font-size:14px; line-height:140%;}
        </style>
    </head>
    <body>
        <div id="container">
            <h1>'.$this->sopa_blackout_page_title.'</h1>
            <div class="sopablackout_padding">
                '.$this->sopa_blackout_message.'
            </div>';
            if($this->sopa_blackout_include_video===true){
                $message .='
                <div class="sopablackout_padding">
                    <iframe src="http://player.vimeo.com/video/31100268" width="600" height="338" frameborder="0" webkitAllowFullScreen mozallowfullscreen allowFullScreen></iframe>
                </div>';
            }
            if($this->sopa_blackout_include_form===true){
                $message .='
                <div class="sopablackout_padding">
                    <iframe src="http://americancensorship.org/callwidget" width="588" height="625" border="0"></iframe>
                </div>';
            }
            $message .='
        </div>
    </body>
    </html>';
            header('HTTP/1.1 503 Service Temporarily Unavailable');
            header('Retry-After: ' . HOUR);
            echo $message;
            exit();
            }
        }

        function sopablackout_checkdate(){
            $toreturn = false;
            if(date('Y-m-d')==$this->sopa_blackout_date){
                if($this->sopa_blackout_timezone){
                    date_default_timezone_set($this->sopa_blackout_timezone);
                }
                if(date('H')>=$this->sopa_blackout_timestart && date('H')<$this->sopa_blackout_timeend){
                    $toreturn = true;
                }
            }
            return $toreturn;
        }

    }

?>

published on Jan 13, 2012 12:00 AM

Read more

jQuery Multi-input for CakePHP

jQuery Multi-input for CakePHP

I apologize for my English! This plugin helps you create are automatically added inputs. They can be used by adding a few pages of the book. men__1@mail.ru for any questions

Code for view:

<?php
echo $this->Html->script('jquery-1.7.1.min');
echo $this->Html->script('jquery.multinput');
echo $this->Form->create();
echo $this->Form->input('User.name');
?>
<div id="multi-input">
    <?php
    echo $this->Form->input('User.Children.multi_i.name');
    echo $this->Form->input('User.Children.multi_i.age');
    ?>
</div>
<?php
echo $this->Form->end('test');
?>
<script>
$(function() {
    $("#multi-input").multinput();
});
</script>

Options for plugin:

  • myPag - Object for paginator. If not passed, the paginator will be posted after the current object.
  • iterator - The string to be replaced by an array index
  • addText - The text for the button to add input
  • hideOld - Hide the new inputs or no

Code for jQuery plugin:

jQuery.fn.multinput = function(options) {
    var options = jQuery.extend({
        myPag: false,
        iterator: "multi_i",
        addText: "Add",
        hideOld: true
    }, options);

    var deffContent;
    var count = 1;
    return this.each(function(){
        var thisM = this;
        deffContent = jQuery(thisM).clone();
        var tmpContent = deffContent.clone();
        tmpContent.find("input").each(function() {
            jQuery(this).attr("name", jQuery(this).attr("name").replace(options.iterator, count));
        });
        jQuery(thisM).html("<div multi_i='" + count + "'>" + tmpContent.html() + "</div>");
        if(options.myPag == false) {
            jQuery(thisM).after("<div id='multi-paginator'></div>");
            var paginator = jQuery("#multi-paginator");
        } else {
            var paginator = options.myPag;
        }
        paginator.html("<ul><li><a class='multi-add' href='#'>" + options.addText + "</a></li><li class='active'><a href='#'>" + count + "</a></li></ul>");
        if(options.hideOld) {
            paginator.find("ul li a").live("click", function() {
                if(!jQuery(this).hasClass("multi-add")) {
                    var id = $(this).text();
                    jQuery(thisM).children().each(function() {
                        if($(this).attr("multi_i") == id) {
                            $(this).show();
                        } else {
                            $(this).hide();
                        }
                    });
                }
            });
        }
        paginator.find("ul li a.multi-add").click(function() {
            count++;
            paginator.find("ul li").removeClass("active").parent().append("<li class='active'><a href='#'>" + count + "</a></li>");
            var tmpContent = deffContent.clone();
            tmpContent.find("input").each(function() {
                jQuery(this).attr("name", jQuery(this).attr("name").replace(options.iterator, count));
            });
            if(options.hideOld) {jQuery(thisM).children().hide();};
            jQuery(thisM).append("<div multi_i='" + count + "'>" + tmpContent.html() + "</div>");
        });
    });
};

Result

Array
(
    [User] => Array
        (
            [name] => menOne
            [Children] => Array
                (
                    [1] => Array
                        (
                            [name] => Max
                            [age] => 34
                        )

                    [2] => Array
                        (
                            [name] => Jon
                            [age] => 23
                        )

                    [3] => Array
                        (
                            [name] => Frad
                            [age] => 5
                        )

                )

        )

)

men__1@mail.ru for any questions

published on Jan 12, 2012 12:00 AM

Read more

CakePHP 2 and launchd on Mac OS X 10.6

CakePHP 2 and launchd on Mac OS X 10.6

To run i.e. maintenance jobs on a regular basis CakePHP provides the availability to write shells which should then be called by cron. Yet on recent Mac OS systems, cron is not the way to go anymore. Instead, there’s “launchd”. I want to show how to use launchd to run a custom shell on a regular time interval.

The shell

The shell itself can be any shell you want and/or have already written. For details on this refer to the cake book, section Creating a Shell.

The command to run the script

In the cakebook in a section close to the one linked above, the writers propose a short shell script which makes sure the paths are set right – however, we don’t need that on our shiny Mac OS systems. Instead, we just call the shell directly using the provided “cake” program: /path/to/your/cake/app/Console/cake yourshell

The launchd stuff

Launchd wants us to create a .plist file with informations about the program we want to run, when we want to run it and so on. I’ve posted an example plist file here, because the bakery doesn’t allow me to post code here...

Since we can give a working directory (in the WorkingDirectory key), we don’t need to use the cakeshell.sh as proposed in the book.

In the StartInterval key we give the time interval after which the program execution should repeat.

To have everything running on boot, save this file to /Library/LaunchDaemons/ – this seems to be an appropriate place since we programmed some sort of server daemon here. It’s probably a good idea to give the file the same name as you label it in the plist file (only that you add .plist as ending...). Alternatively you can also save the file somewhere else and manually load it by calling launchctl load /path/to/your/com.foo.bar.plist, but you’ll have to repeat that after each reboot to have it constantly running.

Feel free to post any questions in the comments, although I probably won’t be able to answer many of them since I’m certainly not an expert on any of those areas! :-)

published on Jan 12, 2012 12:00 AM

Read more

HABTM Add & Delete Behavior for CakePHP 2.0

HABTM Add & Delete Behavior for CakePHP 2.0

The easy way to incrementally add|delete an HABTM association records is to use this Behavior, written by Brandon Parise: HABTM Add and Delete Behavior (posted May 9th 2007) But since it was written by the age of CakePHP v1.2, it seems to malfunction with the current head version of CakePHP Framework, which is 2.0.x - so I’ve came up with a little fixation here.

Updated Version of ExtendAssociationsBehavior for CakePHP 2.0.x

Download

Patch|Diff

$ diff -u old new
--- Vendor/Model/Behavior/ExtendAssociationsBehavior.php    2012-01-10 23:31:14.000000000 +0900
+++ Vendor/Model/Behavior/ExtendAssociations2Behavior.php   2012-01-10 23:33:57.000000000 +0900
@@ -1,5 +1,6 @@
 <?php
-class ExtendAssociationsBehavior extends ModelBehavior {
+App::uses('ModelBehavior', 'Model');
+class ExtendAssociations2Behavior extends ModelBehavior {
     /**
      * Model-specific settings
      * @var array
@@ -44,7 +45,7 @@
             // important to use array_unique() since merging will add
             // non-unique values to the array.
             $data[$assoc][$assoc] = array_unique(am($data[$assoc][$assoc], $assoc_ids));
-            return $model->save($data);
+            return $model->save($data, array('fieldList'=>array($assoc)));
         }

         // association doesn't exist, return false
@@ -82,7 +83,7 @@
                 // which is the ones we want to re-save.
                 $data[$assoc][$assoc] = array_diff($data[$assoc][$assoc], $assoc_ids);
             }
-            return $model->save($data);
+            return $model->save($data, array('fieldList'=>array($assoc)));
         }

         // association doesn't exist, return false
@@ -122,7 +123,7 @@

         // unbind all models except the habtm association
         $this->unbindAll($model, array('hasAndBelongsToMany' => array($assoc)));
-        $data = $model->find(array($model->name.'.'.$model->primaryKey => $id));
+        $data = $model->findById($id);

         $model->recursive = $tmp_recursive;
         $model->cacheQueries = $tmp_cacheQueries;
@@ -149,8 +150,8 @@
      */
     function unbindAll(&$model, $exceptions = array()) {
         $unbind = array();
-        foreach($model->__associations as $type) {
-            foreach($model->{$type} as $assoc=>$assocData) {
+        foreach($model->_associations as $type) {
+            foreach($model->$type as $assoc=>$assocData) {
                 // if the assoc is NOT in the exceptions list then
                 // add it to the list of models to be unbound.
                 if(@!in_array($assoc, $exceptions[$type])) {
@@ -164,3 +165,4 @@
         }
     }
 }
+

Usage

There’s no change in usage/method API:

## add
$model->habtmAdd($assoc_name, $from_id, array($to_id1, $to_id2, ...));
e.g. $this->Post->habtmAdd('PostsTag', 1, array(2, 3));

## delete
$model->habtmDelete($assoc_name, $from_id, array($to_id1, $to_id2, ...));
e.g. $this->Post->habtmAdd('PostsTag', 1, array(3));

## delete all
$model->habtmDeleteAll($assoc_name, $from_id);

Well thats it for now, and thanks Brian for sharing such cool behavior.

published on Jan 11, 2012 12:00 AM

Read more

CakePHP 2.1-alpha just baked

CakePHP 2.1-alpha just baked

We are excited to announce the that the next version of CakePHP just hit alpha state. This version adds several useful features that make CakePHP one of the easiest and more fun to work with frameworks out there. Check it out to enjoy content type specific pages, improved error messages, view blocks and a new callbacks system.

The CakePHP core team is proud to announce the immediate availability of CakePHP 2.1.0 alpha [1]. Version 2.1 is fully backwards compatible with 2.0.x release. This means that if you have an app already working in 2.0 or plan to upgrade one to it, you can safely start using 2.1 right away and expect no additional work in upgrading. We are very excited about several enhancements that are part of 2.1 and are working hard to get the few remaining improvements completed.

In total, there were over 230 commits and over 15 new features or enhancements added to CakePHP 2.1. A complete list of the changes can be viewed in the changelogs page [2]. This is a quick list of this version’s main highlights:

Content Type Views

Two new view classes have been added to CakePHP. The new JsonView and XmlView allow you to more easily generate XML and JSON views.

By enabling RequestHandlerComponent in your application, and enabling support for the xml and or json extensions, you can automatically leverage the new view classes. There are two ways you can generate data views. The first is by using the _serialize key, and the second is by creating normal view files.

This makes it super easy to create content-type specific pages and automatic error responses in the correct mime-types.

Extending views

The View class has a new method allowing you to wrap or ‘extend’ a view/element/layout with another file. This introduces the ideas of “sub-layouts” making your views more flexible than ever, this was implemented using ViewBlocks.

View blocks are a flexible way to create slots or blocks in your views. Blocks replace $scripts_for_layout and $content_for_layout with a more robust and flexible API.

For example blocks are ideal for implementing things such as sidebars, or regions to load assets at the bottom/top of the layout.

Plugin.view

All layout/view/element names can now use Plugin.view to indicate that a plugin view should be used. The plugin option for View::element() is deprecated.

Improved errors

The debug() function output is now cleaner and more readable. We have also added interactive stack traces to exception pages. You can click on each point of the trace to take a peek at the variable state for that point. Also, as mentioned earlier, CakePHP can now respond with content-type specific error pages.

General purpose event system

A new, generic event system has been built and it replaces the way callbacks are dispatched. This should not result in any changes to your code though. You can dispatch your own events and attach callbacks to them at will. This is useful for inter-plugin communication and decoupling of your classes through events.

Testing

Fixtures can be created in datasources other than $test. Models loaded using the ClassRegistry and using another datasource will get their datasource name prepended with test_ (e.g datasource master will try to use test_master in the testsuite)

A new TestShell has been added. It reduces the typing required to run unit tests, and offers a file path based UI:

::
Console/cake test app/Model/Post.php Console/cake test app/Controller/PostsController.php

Helpers

  • <!–nocache–> tags now work inside elements correctly.
  • FormHelper now omits disabled fields from the secured fields hash. This makes working with SecurityComponent and disabled inputs easier.
  • The between option when used in conjunction with radio inputs, now behaves differently. The between value is now placed between the legend and first input elements.
  • The hiddenField option with checkbox inputs can now be set to a specific value such as ‘N’ rather than just 0.
  • The for attribute for date + time inputs now reflects the first generated input. This may result in the for attribute changing for generated datetime inputs.

Callback priorities

Callbacks for Helpers, Behaviors, and Components now support priorities, this helps more easily control the order in which callbacks are fired.

We are working towards making the 2.1 book online in the next few hours and plan to finish the remaining features very soon. Thanks to the ever-growing CakePHP community for the patches, documentation changes and new tickets. Without you there would be no CakePHP!

  • Download a packaged release [1]
  • View the changelog [2]

Links

published on Jan 9, 2012 12:00 AM

Read more

Layout Component

Layout Component

Configurable Layouts for themes I am using Cake 2.0 (beta - havent upgraded properlly yet)

Using themes and redering different view files based on theme, I cam across a limitation which locks you into using the same layouts for view files in each theme. I had a need to change the layout in a new theme so did not want to load the same layout file in app/views/layouts which is dictated by the controller.

So I came up with a configurable approach to loading layouts which removes hardcoding in individual controllers

It involves installing a custom Layout component. This component uses Controller and Action mappings to advise which layout should be loaded and centralises the configuration of layouts in app/config/core.php

The Layout Component class is here

<?php
class LayoutComponent extends Object {

    public function beforeRedirect(&$controller, $url, $status = null, $exit = true){}
    public function beforeRender(&$controller){}
    public function initialize(&$controller, $settings = array())
    {
        $this->controller = &$controller;
        if (is_array(Configure::read('App.controller.layouts'))) {
            $layoutMap = Configure::read('App.controller.layouts');
            foreach ($layoutMap as $key => $value) {
                if ($key == $this->controller->name) {
                    if (is_array($value['action'])) {
                        // many action mappings apply but maybe not all
                        if (in_array($$this->controller->action, $value['action'])) {
                            if (isset($value['layout'])) {
                                $this->controller->layout = $value['layout'];
                            }
                        }
                    } else if (isset($value['action']) && $value['action'] == '*') {
                        // All actions mappings apply
                        if (isset($value['layout'])) {
                            $this->controller->layout = $value['layout'];
                        }
                    }
                }
            }
        }
    }
    public function shutdown(&$controller){}
    public function startup(&$controller){}
}

To use it simply load it into your controller or AppController’s component array

eg:

public $components = array(
        'Layout'
    );

To configure layouts here is the setting to place in your core.php file

Configure::write('App.controller.layouts', array(
    'Pages' => array('action' => '*', 'layout' => 'my_layout')
    ));

The above configuration says load a layout file called ‘my_layout’ if the controller requested is called ‘Pages’ and do this for any of ‘Pages’ actions

You can also single out actions in your configuration like so

Configure::write('App.controller.layouts', array(
    'Pages' => array('action' => array('home'), 'layout' => 'my_layout')
    ));

The above configuration says load the ‘my_layout’ file only when the requested controller name is ‘Pages’ and the action of this controller is ‘home’. All other actions will use the default layout still.

You can list as many controllers as required in the configuration like so;

Configure::write('App.controller.layouts', array(
    'Pages' => array('action' => '*', 'layout' => 'my_layout'),
    'Searches' => array('action' => array('index'), 'layout' => 'search_layout')
    ));

This may be useful to you and keeps your controllers cleaner and more configurable.

published on Jan 5, 2012 12:00 AM

Read more

Adding a TinyMCE image browser to CakePHP 2.+

Adding a TinyMCE image browser to CakePHP 2.+

This is just and update to Adding a TinyMCE image browser the CakePHP way as applicable to the 2.+ versions of Cake. Nothing major, just following with the api changes to make this work smoothly. Here is the updated Model code: ` <?php App::uses(‘Folder’,’Utility’); App::uses(‘File’,’Utility’);

classImageuploadextendsAppModel{

var$name=’Imageupload’;

var$validate=array( ‘imageupload’=>array( ‘rule’=>array( ‘validFile’, array( ‘required’=>true, ‘extensions’=>array( ‘jpg’, ‘jpeg’, ‘gif’, ‘png’ ) ) ) ) );

var$useTable=false;

functionreadFolder($folderName=null){ $folder=newFolder($folderName); $images=$folder->read( true, array( ‘.’, ‘..’, ‘Thumbs.db’ ), true ); $images=$images[1];//Weareonlyinterestedinfiles

//Getmoreinfosabouttheimages $retVal=array(); foreach($imagesas$the_image) { $the_image=newFile($the_image); $retVal[]=array_merge( $the_image->info(), array( ‘size’=>$the_image->size(), ‘last_changed’=>$the_image->lastChange() ) ); }

return$retVal; }

functionupload($data=null){ $this->set($data);

if(empty($this->data)){ returnfalse; }

//Validation if(!$this->validates()){ returnfalse; } //print_r($this->data); //Movethefiletotheuploadsfolder if(!move_uploaded_file($this->data[‘Imageupload’][‘Image’][‘image’][‘t mp_name’],WWW_ROOT.DS.’uploads’.DS.$this->data[‘Imageupload’][‘Image’] [‘image’][‘name’])){ returnfalse; }

returntrue; }

functionvalidFile($check,$settings){ $_default=array( ‘required’=>false, ‘extensions’=>array( ‘jpg’, ‘jpeg’, ‘gif’, ‘png’ ) );

$_settings=array_merge( $_default, ife( is_array($settings), $settings, array() ) );

//RemovefirstlevelofArray $_check=array_shift($check);

if($_settings[‘required’]==false&&$_check[‘size’]==0){ returntrue; }

//Nofileuploaded. if($_settings[‘required’]&&$_check[‘size’]==0){ returnfalse; }

//CheckforBasicPHPfileerrors. if($_check[‘error’]!==0){ returnfalse; }

//UsePHPsownfilevalidationmethod. if(is_uploaded_file($_check[‘tmp_name’])==false){ returnfalse; }

//Validextension returnValidation::extension( $_check, $_settings[‘extensions’] ); } } ?> ` You’ll notice a couple of small changes, mainly addin the App:uses functionality before the class declaration, and also i renamed it to Imageuploads, as Images redirected to the webroot/images folders.

And here is the updated Controller code:

<?php
classImageuploadsControllerextendsAppController{

var$name='Imageuploads';

var$uses=array('Imageupload');

var$helpers=array(
'Html',
'Form',
'Js',
'Number'//Usedtoshowreadablefilesizes
);

functionadmin_index(){
$this->layout='admin';
$this->set(
'images',
$this->Imageupload->readFolder(WWW_ROOT.DS.'uploads')
);
}

functionadmin_upload(){
//Uploadanimage
if(!empty($this->data)){
//Validateandmovethefile
if($this->Imageupload->upload($this->data)){
$this->Session->setFlash('Theimagewassuccessfullyuploaded.');
}else{
$this->Session->setFlash('Therewasanerrorwiththeuploadedfile.');
}

$this->redirect(
array(
'action'=>'index'
)
);
}else{
$this->redirect(
array(
'action'=>'index'
)
);
}
}
}
?>
<p>Iaddedtheadmin_partbecausethisfunctionalityisbehindanauthsystemandI
wantedconsistentURI'sbutthatisuptotoyou.</p>
<p>Hereisthetinymce.ctpcode</p>
<?phpecho$this->Html->script("tiny_mce/tiny_mce.js");?>

<?php
echo$this->Html->scriptBlock(
"functionfileBrowserCallBack(field_name,url,type,win){
browserField=field_name;
browserWin=win;
window.open('".Helper::url(array('controller'=>'imageuploads'))."','br
owserWindow','modal,width=600,height=400,scrollbars=yes');
}"
);
?>

<?php
echo$this->Html->scriptBlock(
"tinyMCE.init({
mode:'textareas',
theme:'advanced',
theme_advanced_buttons1:'forecolor,bold,italic,underline,|,justifyleft
,justifycenter,justifyright,justifyfull,|,bullist,numlist,|,undo,redo,
|,link,unlink,|,image,emotions,code',
theme_advanced_buttons2:'',
theme_advanced_buttons3:'',
theme_advanced_toolbar_location:'top',
theme_advanced_toolbar_align:'left',
theme_advanced_path_location:'bottom',
extended_valid_elements:'a[name|href|target|title|onclick],img[class|s
rc|border=0|alt|title|hspace|vspace|width|height|align|onmouseover|onm
ouseout|name],hr[class|width|size|noshade],font[face|size|color|style]
,span[class|align|style]',
file_browser_callback:'fileBrowserCallBack',
width:'620',
height:'480',
relative_urls:false
});"
);
?>

And lastly the the index (or admin_index in my case) view located in View/imageuploads/:

<?php
echo$this->Html->scriptBlock(
"functionselectURL(url){
if(url=='')returnfalse;

url='".Helper::url('/uploads/')."'+url;

field=window.top.opener.browserWin.document.forms[0].elements[window.t
op.opener.browserField];
field.value=url;
if(field.onchange!=null)field.onchange();
window.top.close();
window.top.opener.browserWin.focus();
}"
);
?>

<?php
echo$this->Form->create(
null,
array(
'type'=>'file',
'url'=>array(
'action'=>'upload'
)
)
);
echo$this->Form->label(
'Image.image',
'Uploadimage'
);
echo$this->Form->file(
'Image.image'
);
echo$this->Form->end('Upload');
?>

<?phpif(isset($images[0])){
$tableCells=array();

foreach($imagesAs$the_image){
$tableCells[]=array(
$this->Html->link(
$the_image['basename'],
'#',
array(
'onclick'=>'selectURL("'.$the_image['basename'].'");'
)
),
$this->Number->toReadableSize($the_image['size']),
date('m/d/YH:i',$the_image['last_changed'])
);
}

echo$this->Html->tag(
'table',
$this->Html->tableHeaders(
array(
'Filename',
'Size',
'Datecreated'
)
).$this->Html->tableCells(
$tableCells
)
);
}?>

You’ll notice a few small differences, like $this->Html->scriptBlock

Finally just make sure you add Element(‘tinymce’); ?> to the form you want to add this to. Cheers!

published on Jan 4, 2012 12:00 AM

Read more