FAQ: Fields/columns/attributes can be added in the constructor, in meta(), and in postMeta(). When should each be used?
Constructor
Discouraged (??? why?)
meta()
As much as possible should be defined in meta() so that the results can be
cached. (Presumably this enables nodes to be created faster.)
this leads to faster node If you can defined Should be declared "static" so that it can be cached. (The system appears to use
Things that don't work:
- Constants, including flags.
#
- discouraged (??? why?)
meta()- should be defined "static" so can be cachedpostMeta()- if the fields added depend on the data itself
In an atkMetaNode, what is the difference between meta and postMeta?
meta is cached (if declared static, which it should be), postMeta can do
more stuff.
FAQ: Why don't flag constants work in meta()?
Unlike postMeta, which loads the
FAQ: When should fields be added in postMeta, and when in the constructor?
(Adding a field in postMeta that has already been added "reconfigures" the
existing field, but doesn't changes its order.)
FAQ: How can I control the order in which attributes (fields/columns) appear an edit form?
You pretty much have to set it explicitly, either via
atkMetaPolicy::setNodeOrder(), atkMetaPolicy::setIncludes() or the
$order arguments to atkMetaNode::add() or atkMetaPolicy::add().
Both atkMetaNode::add() and atkMetaPolicy::add() appear to preserve the
order attributes are added, but in reality the attributes have been added
before you get a chance to call add, and your call merely reconfigures an
existing attribute.
You can change the order by calling atkMetaNode::add() from your
constructor, but adding fields in the constructor is discouraged for some
reason.
FAQ: How can I find the id an attribute will get when rendered as HTML?
(Useful for writing JavaScript code that displays or hides a attributes as values change.)
FAQ: How to translate to/from the meta()/postMeta() ways of adding attributes?
public function postMeta() {
$this->add(new atkMyClass($column_name, $arg1, $arg2, $arg3));
}
corresponds to
public static function meta($policy) {
$policy->add($column_name, "atkMyClass", array($arg1, $arg2, $arg3));
}
Note: Whatever arguments need to be provided to the atkMyClass constructor
must also be provided in the array that is the third argument to
atkMetaPolicy::add(). The documentation for atkMetaPolicy::add() lists
$flags as an optional fourth argument, and $order as an optional sixth
argument, suggesting that these are somehow automatically passed to the
atkMyClass constructor when the time comes to instantiate the object.
However, this is not the case.
(I don't know what happens if e.g. $flags is specified in both places.
Presumably one overwrites the other?)
Note: In meta(), you may be required to need to manually load flag
constants. For example, if you want to use the flag AF_BOOL_INLINE_LABEL
you'll need to do this:
useattrib('atkboolattribute');
class MyClass {
// ...
}
FAQ: How to create a "dummy" attribute?
For example, to create an "attribute" whose value is derived from other values.
See atkDummyAttribute.
You can also transform a conventional attribute into one that never touches the database by setting the following flags:
$attr->setLoadType(NOLOAD)
$attr>setStorageType(NOSTORE)
FAQ: How do you determine which attributes/columns appear in "list" view?
To add attributes from a OneToOne or ManyToOne relation, use
addListColumns:
// in postMeta()
$this->getAttribute('artist')->addListColumn('name');
(There doesn't seem to be an analogous way to remove columns.)
FAQ: How do you determine which attributes/columns appear in "detail" view?
TIP: How to change or translate ATK-generated (template) text
(Including labels.)
Some text is defined explicly in code, whilst other bits come automagically from language files.
(Initial first capital letter conversion.)
- attributename
- linkattributenameadd
- linkattributenameedit
- linkselectattributename
- tab_attributename
nodenameattributenametooltip
adminHeader()adminFooter()http://www.atk-framework.com/wiki/Renaming_%27add%27_and_%27select%27_links_in_relations
- http://www.atk-framework.com/wiki/Controlling_On_Screen_Text_and_Help
FAQ: How do I "fake" an attribute?
There are a few ways of doing this.
The simplest way, which works if you want (or need) complete control over
the HTML output of the label and value, is to use an atkDummyAttribute:
// in meta()
$policy->add("myattribute", "atkDummyAttribute", array("my value", AF_DUMMY_SHOW_LABEL));
(The value of the label is defined in the language file.)
You need to supply the AFDUMMYSHOW_LABEL flag because by default, atkDummyAttributes don't display a label. Note that
$policy->addFlag('requested_article', AF_DUMMY_SHOW_LABEL);
won't work, because AF_DUMMY_SHOW_LABEL isn't a regular flag; it's a
message to the constructor to either add the AF_BLANKLABEL flag (or not).
If the value is dynamic (e.g. derived from another field), then you can add
an appropriate *_edit() method:
public function myattribute_edit() {
return "some text";
}
If you want ATK to generate some of the HTML for you (for example, if your "fake" value is a date, and you want ATK's date picker to be displayed), then you need to create the appropriate attribute and configure it to never touch the database:
// in postMeta()
$att = $this->add(new atkAttribute("myattribute"));
$att->setLoadType(NOLOAD);
$att->setStorageType(NOSTORE);
In this case you can't use myattribute_edit() to generate the value,
because myattribute_edit() is expected to return HTML. Instead, you need
to modify preAddToEditArray():
public function preAddToEditArray(&$record) {
$record["date"] = array (
'day' => '11', 'month' => '07', 'year' => '2008',
'hours' => '12', 'minutes' => '11', 'seconds' => '00'
);
}
(Better to use initial_values() for this?)
Although if appropriate to the situation, it's safer to use an built-in parser:
public function preAddToEditArray(&$record) {
$att = $this->getAttribute("date");
$record["date"] = $att->db2value(array_merge($record, array("date" => "2008-07-11 12:11:00")));
}
Other types of "fake" attributes:
atkParserAttribute- ???
FAQ: How can I write an (raw) array to the database?
You can commit a "raw" array to the database with atkNode::addDb():
$node = atkGetNode("users.customer");
$node->addDb(array(
name => "Michael",
email => "mjs@beebo.org"
));
To update, ensure that the key atkprimkey is defined and call updateDb
instead. You will probably need to explicitly tell the node which attribute
has changed:
public function postUpdate(&$record) {
$record["status"] = 5;
$this->getAttribute('status')->setForceUpdate(true);
$this->updateDb($record);
// ...
}
To select:
$node = atkGetNode("users.customer");
$result = $node->selectDb();
FAQ: 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 doesn't work. Here are a few pitfalls:
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 classato ensure that this relation can be found from classb. (A similar problem may occur withatkManyToManyRelation.)The symptom of this problem 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_projectthat is derived fromproject. (i.e.class customer_project extends project { ... }.) In this case,projecthas 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 isproject_id, and the solution to this problem is to make the join column name explicit:$this->setLocalKey('project_id');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
adefines a relation as follows:$policy->hasOne("quux");then in
athis will be interpreted asfoo.quux, whilst inbit will be interpreted asbar.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");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');
EXAMPLES: Using hasOne()
The first argument to hasOne() is always a node name.
If you have a table with the columns
created_user_id
updated_user_id
both of which reference the user table, this can be modelled by either:
$policy->add('created_user_id', 'atkManyToOneRelation', array('users.employee'));
$policy->add('updated_user_id', 'atkManyToOneRelation', array('users.employee'));
or
$policy->hasOne('users.employee', array('source' => 'created_user_id'));
$policy->hasOne('users.employee', array('source' => 'updated_user_id'));
FAQ: What's the equivalent of include or require for modules?
Use atkimport in the module_preload.inc file in the root of the module
directory. e.g. to inherit from the node projects.project from the
customer_portal module, create a
modules/customer_portal/module_preload.inc file with the contents:
<?php
atkimport('module.projects.project');
?>
FAQ: Raw SQL queries?
$query = atkQuery::create();
$query->addTable('quote_tender_article', 'qta');
$query->addCondition('qta.quote_tender_id = ' . (int)$record['quote_tender_id']['id']);
$query->addField('qta.requested_article_id');
$result = $query->executeSelect();
See http://www.atk-framework.com/wiki/Database_Access.
Important Types
atkPage - atkNode::getPage()
atkPage::registerscript(); atkPage::registerloadscript();
/**
* Get the page instance of the page on which the node can render output.
* @return atkPage The page instance.
*/
function &getPage()
{
$page = &atkinstance("atk.ui.atkpage");
return $page;
}
/**
* Get the ui instance for drawing and templating purposes.
*
* @return atkUi An atkUi instance for drawing and templating.
*/
function &getUi()
{
$ui = &atkinstance("atk.ui.atkui");
return $ui;
}
/**
* Returns the lock mode.
*
* @return int lock mode (atkLock::EXCLUSIVE, atkLock::SHARED)
*/
public function getLockMode()
{
return $this->m_lockMode;
}
Flag subtleties:
If constant undefined, flag doesn't get set.
The role of magic.
Flags used inconsistently--e.g. in a case where flag is checked in constructor only.
HOWTO: Change text
Use module-specific language file:
$this->text('something');
Use global language file:
atktext('something');
Use setLabel on an attribute:
$attr->setLabel('something');
setLabel is the most specific, and will override other settings. This
means that, for example, if a base class calls setLabel on an attribute in
postMeta(), the only way to override it is to call setLabel in the
derived class's postMeta().
FAQ: How to "manually" read/load/access a node/record?
$node = newNode("moderation.deletereason");
$node->addFilter("moderation_delete_reason_id", 773);
$record = $node->select(); // $record is an array
FAQ: How to "manually" save a node/record?
$node = newNode("moderation.deletereason");
$node->updateDb($record); // $record is an array
atkGetDb()->commit(); // Transactions are not automatically committed!
GLOSSARY
- module
- node
- attribute
FAQ: How can I construct a URL?
There are several URL-building methods and functions:
atkHref(equivalent toatkSessionManager::href)dispatch_urlatkController::dispatchUrl
atkHost may also be useful if you need the host name.