This guide describes how to code for the Gallery 2 framework to make sure that it works on all platforms and as reliable as possible as well as that it is compatible with Gallery 2's requirements.
This document does not cover the the Gallery 2 Coding Standards, that is, the coding style is described elsewhere.
Database
- Do not use DBMS dependent SQL fragments. Some DBMS dependent SQL is abstracted in $storage->getFunctionSql(), e.g. BIT_OR, BIT_AND, etc.
- Do not call database related methods directly (e.g. mysql_connect). Instead use the Gallery 2 methods.
global $gallery;
list ($ret, $results) = $gallery->search('SELECT * FROM [GalleryPhotoItem]');
- Do not modify Map tables directly. Use GalleryCoreApi::addMapEntry($mapName, ..), ::removeMapEntry, .. instead.
- Note: In G2.0, this was MapNameMap::addMapEntry() etc.
- Do not create your own database queries unless it's really necessary. Instead use Gallery 2's API methods.
- Do not use DDL (the CREATE TABLE, ALTER TABLE, ... subset of the SQL language). Instead, use the Entity classes and Maps.xml including the XML descriptions to create new or modify existing tables if necessary. Gallery 2 will then generate SQL code for all supported DBMS once you run make in the classes/ directory.
- Locking: Use Read and write locks when you need to update persistent data (data that is stored in database). Do not forget to release the locks once you're finished.
- Hint: lockIds are not the same as itemIds.
Large Datasets
- When dealing with large datasets, think about using a progress bar and $storage->checkPoint to minimize the effect of a possible fatal timeout / error.
- Do not query with WHERE / UPDATE clauses that scale in query string size by the number of arguments since the query size is limited. Instead, do it in smaller batches.
As an example of a bad WHERE / UPDATE clause, assume $allItemIds is a list of 1000+ ids:
$gallery->search("SELECT * FROM [GalleryItem] WHERE [GalleryItem::id] IN ($markers)", $allItemIds);
- Note: GalleryCoreApi::loadEntitiesById() and GalleryCoreApi::acquire*Lock() are both not yet fixed. This means that you should call these methods with smaller batches too. Even once they are fixed to do the work in batches, you will still have the problem of webserver (not php) timeouts. We can't use a progress bar deep down in the API since we don't know if the current view supports a progress bar.
PHP
- Do not call die / exit / header('Location: ...') in your code. Instead, return a proper status / redirect url in your views/controllers. This way Gallery 2 has the chance to commit/rollback open transactions, do some cleanup, and apply patches to bugs (e.g. header('Location:') is buggy on some platforms and we fix it at the end of the request).
- For PHP functions that are listed in modules/core/classes/GalleryPhpVm.class, use
global $gallery;
$phpVm =& $gallery->getPhpVm();
$phpVm->functionName();
- Compatibility: G2 code must run with PHP 4 and 5, that is PHP 4.1.0+ (as of G2.2 it'll be 4.3.0+) and PHP 5.0.4+. Do not use any "PHP 5"-only OO code and do not use any methods that are not available in PHP 4.1.0 unless you provide a fallback solution.
if (function_exists('foo_bar')) {
foo_bar($data);
} else {
myFooBar($data);
}
Filesystem/Platform
- Do not call any filesystem / platform functions directly (e.g. fopen, fsockopen, exec, chmod, ...). Use the Gallery 2 methods instead.
global $gallery;
$platform =& $gallery->getPlatform();
$platform->fopen($path);
Strings/Texts and Translation
- For all strings / texts that the end user gets to see, use
$plugin->translate('Some text')
If the text is going into the database and translate() is called when retrieving it from the database, use
$gallery->i18n('Some text')
In smarty templates:
{g->text text="Some text"}
- Note: Exceptions are the optional messages in GalleryStatus objects, and unit test failure messages which do not use translate().
- If you're using HTML in your string write it using the translation method.
/* Bad */
$plugin->translate('Do <b>NOT</b> do this!');
/* Good */
$plugin->translate(array('text' => 'Do %sNOT%s do this!', 'arg1' => '<b>', 'arg2' => '</b>'));
- Also use the translate arguments when the string includes variables.
/* Bad */
$plugin->translate("Next, please read chapter '$chapter'");
/* Good */
$plugin->translate(array('text' => "Next, please read '%s'", 'arg1' => $chapter));
In smarty templates:
{g->text text="Next, please read '%s'" arg1=$chapter}
Misc
- URL Generation: Generate all URLs using methods provided by Gallery.
In PHP:
global $gallery;
$urlGenerator =& $gallery->getUrlGenerator();
$url = $urlGenerator->generateUrl($params, $options);
In smarty templates:
{g->url arg1= ....}
- Modifying code: Do not modify the code of existing modules. Instead, extend the feature set of Gallery 2 with additional modules. Reason: Users should be able to administer Gallery 2 with a simple web-interface. Adding a new feature should be as easy as installing a new module with a few mouse clicks. We don't want hacky installation instructions like "open file X, find line Y, replace A with B, ...". If you need a change in an existing module, please talk to the module author if this change could be incorporated in the existing module, preferably in a modular way (Factory Registrations), e.g. a module could check in the G2 factory if there are plugins for this module and your new module could register a plugin for the other module, thus extending the functionality in a modular way.