ATK FAQ

From Achievo/ATK Wiki

Jump to: navigation, search

Contents

General Questions

Where can I go if this FAQ doesn't answer my question?

The Forum is helpful to get answers to any questions you might have that are not covered here. Also have a look at the many howto's that are available for ATK.

atkMetaNode Questions

Special attribute flags don't seem to work in the meta method

This is one of the biggest gotchas about the meta functionality, special attribute flags like AF_BOOL_* or AF_MANYTOONE_* are defined in the attribute/relation, but, unless you explicitly include the attribute/relation in question by putting 'useattrib('atkboolattribute');' or 'atkrelation('atkmanytoonerelation');' at the top of the file you can't use the flags (the autoload can't include for missing constants).

So if you want to use such Attribute Flags, use:

  useattrib("atkboolattribute");

What is the difference between meta() and postMeta() ?

Broadly speaking, the 'meta' method is 'pre-compile' (where the meta stuff compiles to an atkNode) and the postMeta is 'post-compile'. Because we want to be able to cache as much as possible it's a good idea to configure your node as much as possible in the meta method.

Use of the constructor in atkMetaNodes is discouraged, why?

Use of the constructor in atkMetaNodes is discouraged because you should be able to most things in the meta static method and everything else in the postMeta. Using the constructor is reserved for normal nodes and will lead to confusion with developers that have to maintain/extend your functionality.

How can I improve performance of an atkMetaNode?

Remember to define the meta method as a static, to enable caching!

I'm trying to inherit from a node but it doesn't work as expected--what might be wrong?

(i.e. my class fails the "empty subclass test".)

Suppose you have:

$node = newNode("foo.a");

ATK supports node inheritance whereby

$node = newNode("bar.b");

will work exactly the same as before if

class b extends a { }

However, sometimes this doesn't work. Here are a few pitfalls:

  1. Some relations try to guess column names, which sometimes goes wrong when the class name changes. For example, if one of the relations is an atkManyBoolRelation, you may need to add a call to

    $bool->setLocalKey('a_id');

    from the postMeta() of class a to ensure that this relation can be found from class b. (A similar problem may occur with atkManyToManyRelation.)

    The symptom of this problem is a fatal error that's something like:

    Unknown column name (Unknown column 'project_supplier_selection.customer_project' in 'where clause').
    

    You may get an error like this if you're trying to create a class, customer_project that is derived from project. (i.e. class customer_project extends project { ... }.) In this case, project has an attribute that's joined via a many-to-many relation, and the code is using the class name to guess the appropriate join column. (Note that the unknown column, customer_project, has the same name as the derived class.) In this case, the appropriate join column is project_id, and the solution to this problem is to make the join column name explicit:

    $rel->setLocalKey('project_id');
  2. If a node name is not fully-qualified with the module name, then in some places ATK assumes that it is part the current node. e.g. if node foo defines a relation as follows:

    $policy->hasOne("quux");

    then in foo this will be interpreted as foo.quux, whilst in node bar it will be interpreted as bar.quux, which may not exist. (If this is the case, a symptom will be an editing screen with all the fields blank.) To fix this, fully qualify the module names:

    $policy->hasOne("foo.quux");

    Note that this applies to constructions like:

    $policy->hasMany("foo", array(), array("through" => "foo"));

    which needs to be converted to:

    $policy->hasMany("module.foo", array(), array("through" => "module.foo"));
  3. If the base module has not been included, you'll get a "Class 'XXX' not found" error. To fix this, import the base class from module_preload.inc:

    atkimport('module.projects.project');

    (This is the ATK equivalent of include/require.)

Record list Questions

How can I delete multiple records at once?

Add the flag NF_MULTI_RECORD_ACTIONS or NF_MRA (shorter version) to the node, like this:

In a regular node:

  public function __construct()
  {
    parent::__construct("mynode", NF_MRA);
    ...

In a meta node:

  class mynode extends atkMetaNode
  {
    protected $flags = array(NF_MRA);
    ...

How do I change the action icons that appear in a recordlist?

See the Custom Record Actions HOWTO for information on custom actions, including information on adding an icon that calls an existing action.

Attribute Questions

How can I force an attribute to save when it's hidden?

If you set AF_HIDE on an attribute, ATK assumes that its value doesn't change, so it will not save or update the value. If you want to force the value to be saved, you can do the following.

For forced updates:

$attr->setForceUpdate(true);

For forced inserts:

$attr->setForceInsert(true);

How can I manually give a record a certain value for a field?

One gotcha that a lot of new developers run into is that ATK has it's own internal representation of data from attributes and relations. You usually come across it when trying to manually add values to a node with the addDb/updateDb or setting data in a record in the preAdd/preUpdate triggers. For instance, where you get a plain string in the YYYY-MM-DD string format from the database for a date field, ATK will convert this (with the db2value method) to an array with the 'year','month' and 'day' values. So if you try this: $record['mydate'] = '2008-09-19'; ATK won't store it. You have to use the internal format.

To convert a string value to the internal representation as used by the attribute, use:

  $attr = $this->getAttribute("mydate");
  $record["mydate"] = $attr->parseStringValue("2008-09-19");

How can I implement my own validation logic on a field?

See this howto: Custom Validation Logic

How can I validate a file before upload?

The atkFileAttribute has a validate method that you can override, as documented in the Custom Validation Logic documentation. However, when it's validating, you don't have the actual file yet (it will only really save the file after everything is valid).

So, if you want to check the file itself during validation, you can get $record["picture"]["tmpfile"] and process that, e.g.:

public function picture_validate(&$record, $mode)
{
    // find out the size of the file they want to upload.
    $size = getimagesize($record['picture']['tmpfile']);
    $width = $size[0];
    $height = $size[1];
    if ($width > 400 || $height > 400) {
        triggerError($record, "picture", "You can upload only pictures smaller than 400 pixels in height and width");
    }
}

How can I use an attribute when I don't want to store it in, or load it from, the database?

If you want to add an attribute that isn't tied to a database value, e.g. to just use as a search parameter etc., you can use the following snippets:

  $attr->setStorageType(NOSTORE); // attribute will never be saved to the database
  $attr->setLoadType(NOLOAD); // attribute will never be loaded from the database

Note that if you only use NOSTORE, you might run into trouble if the field doesn't exist in the database. Even when deleting a record, the current value is retrieved from the database. To make sure that doesn't fail, always use both NOSTORE and NOLOAD if a field does not exist in the db.

Miscellaneous Questions

What's the difference between newNode($node) and atkGetNode($node)?

atkGetNode() caches return values; multiple calls to atkGetNode() with the same argument will return exactly the same node object (i.e. the exact same object in memory).

newNode() creates a new node (new object in memory) every time.

If one of the things you want to do with the returned node is call addFilter() on it, you almost certainly want newNode(). In most cases however, you will want to use atkGetNode() for performance reasons.

How can I use an existing SQL query with ATK?

i.e. how to use "raw SQL" with ATK.

There are a few different approaches to adapting an existing SQL query for use with ATK depending on what you want to do.

See the Database Access howto for the various approaches.

Development Questions

How can I turn on debugging dynamically?

See the Turning on debugging at runtime howto.

Can I write the debug output to a file?

If you set '$config_debuglog' to a www-user-writable file, your application will write all debugging that is registered to be shown to this file. This is very useful for situation where the debugging is registered but never shown (because of a recursive error causing Apache to segfault). Please note that it's not a good idea to turn this on in staging applications as you may not be the only one making requests on the application with debugging on. And remember to turn this off! Because you can imagine that this file may grow quite a bit over time :)

Personal tools
Navigation