Thứ Tư, 28 tháng 5, 2014

So What Exactly Is a Node? [Working with Nodes]

One of the first questions asked by those new to Drupal development is, What is a node?” A node is a piece  of content.
Drupal assigns each  piece  of content an ID number called  a node ID (abbreviated in the code  as $nid). Generally each
node has a title also,to allow an administrator to view a list of nodes by title.

There are many different kinds  of nodes, or node types. Some common node types  are “blog entry,” “poll,” and  forum.”Often  the term content type is used as a synonym for node type, although a node type is really a more abstract concept and can bethought of as a derivation of a base  node, as Figure  7-1 represents.

The beauty of all content types  being nodes is that they’re based on the same underlying data structure. For developers, this means that for many operations you can treat all content the same programmatically. It’s easy to perform batch operations onnodes, and  you also get a lot of functionalitfor custom content types  out of the box. Searching, creating, editing, and 
managing content are supported natively by Drupal because of the underlying node data structure and  behavior. This uniformity is apparent to end  users, too. The form for creating,editing, and  deleting nodes have similar look and  feel, leading to a consistent and  thus easier-to-use interface.

Figure 7-1. Node types are derived  from a basic node and may add fields.


Node  types  extend the base  node, usually by adding their own data attributes. A node of type poll stores voting  options such as the
duration of the poll, whether the poll is currently active,  and  whether the user  is allowed to vote. A node of type forum loads  the
taxonomy term for each  node so it will know where it fits in the forums defined by the administrator. blog nodes, on the other hand,dont add any other data. Instead, they just add  different views into the data by creating blogs for each  user and  RSS feeds for
each  blog. All nodes have the following attributes stored within the node and  node_revisions database table:

     nid: A unique ID for the node.
     vid: A unique revision ID for the node, needed because Drupal can store content revisions for each  node. The vid is unique
across all nodes and  node revisions.
     type: Every node has a node type—for example, blog story, article, image, and so on.
     language: The language for the node. Out of the box, this column is empty, indicating language-neutral nodes.
     title: A short 255-character string used as the node’s title, unless the node type declares that it does not have a title, indicated by
a 0 in the has_title field of the node_type table.
     uid: The user  ID of the author. By default, nodes have a single author.
     status: A value of 0 means unpublished; that is, content is hidden from those who dont have the administer nodes permission.
A value of 1 means the node is published and  the content is visible to those users with the access content” permission.The display of a published node may be vetoed by Drupal’s node- level access control system (see the “Limiting Access to a Node  Type with
hook_access() and  Restricting Access to Nodes” sections later in this chapter). A published nodewill be indexed by the search module if the search module is enabled.
     created: A Unix timestamp of when the node was created.
     changed: A Unix timestamp of when the node was last modified. If you’re using the node revisions system, the same value is
used for the timestamp field in thnode_revisions table.
     commentAn integer field describing the status of the node’s comments, with three possible values:
      0: Comments have been disabled for the current node. This is the default value for existing nodes when the comment module is
disabled. In the user interface of the node editing form’s “Comment settings” section, this is referred to asDisabled.
      1: No more comments are allowed for the current node. In the user interface of the node editing form’s Comment settings
section, this is referred to as “Read only.”
      2: Comments can be viewed,  and  users can create new comments. Controlling who can create comments and  how comments appear visually is the responsibility of the comment module. In the user interface of the node editing form’s “Comment settings” 
section, this is referred to as Read/Write.
     promote: An integer field to determine whether to show  the node on the front  page, with two values:
      1: Promoted to the fron page.  The node is promoted to the default front page of your site. The node will still appear at its normal page,  for example, http://example.com/?q=node/3. It should be noted here  that, because you can changewhich page is considered the front  page of your site at Configuration -> Site information, “front page” can be a misnomer. It’s actually more accurate to say the http://example.com/?q=node page will contain all nodes whose promotefield is 1. The URL http://example.com/?q=node is the fron page by default.
      0: Node  isn’t shown on http://example.com/?q=node.
     sticky: When  Drupal displays a listing  of nodes on a page,  the default behavior is to list first those nodes marked as sticky, and  then list the remaining unsticky nodes in the list by date  created. In other words, sticky nodes stick to the top ofnode listings. A value of 1 means sticky, and  a value of 0 means, well, unsticky. You can
have multiple sticky nodes within the same list.
     tnid: When a node serves  as the translated version of another node, the nid of the source node being translated is stored here. For example, if node 3 is in English and node 5 is the same content as node 3 but in Swedish, the tnid field of node 5will be 3.
     translate: A value of 1 indicates that the translation needs to be updated; a value of 0 means translation is up to date.

If you’re using  the node revisions system, Drupal will create a revision of the content as well as track who made the last edit.

Not Everything Is a Node

Users,  blocks, and  comments are not nodes. Each of these specialized data structures has its own hoosystem geared toward its intended purpose. Nodes (usually) have title and  body content, and  a data structure representing a user doesn’t need that. Rather,users need an e-mail address, a username, an safe way to store passwords. Blocks are lightweight storage solutions for smaller pieces
of content sucas menu navigation, a search box, a list of recent comments, and  so on. Comments aren’t nodes either, which keeps
them lightweight as well. It’s quite possible to have 100 or more comments per page,  and  ieach  of those comments had to go
through the node hook system when being loaded, that would be a tremendous performance hit.

In the past, there have been great  debates about whether users or comments should be nodes, and some contributed modules actually implement this. Be warned that raising this argument is like shouting “Emacs is better!” at a programming convention.

Creating a Node Module

Traditionally, when you wanted to create a new content type in Drupal, you would write a node module that took responsibility for providing the new and  interesting things your content type needed. We say “traditionally” because recent advents within theDrupal framework allow you to create content types within the administrative interface and  extend their  functionality with contributed modules rather than writing a node module from scratch. I’ll cover both solutions within this chapter.

I’ll write a node module that lets users add a job posting to a site. A job posting node will include a title, a body where the details of the job posting will be entered, and  a field where the user can enter the name of the company. For the job posting title and a body,I’ll use the built-in node title and  body that are standard with all Drupal nodes. I’ll need to add a new custom field for the
company’s name. I’ll start by creating a folder named job_post in your sites/all/modules/custom directory.

Creating the .install File

The install file for the job pos module performs all of the set-up operations for things like defining the node type,
creating the fields that make up our new node type, and  handling the uninstall process when an administrator uninstalls the module

<?php
/**
*   @file
*   Install file for  Job Post  module.
*/
/**
*   Implements hook_install().
*   - Add  the  body field.
*   - Configure  the  body field.
*   - Create  the  company  name field.
*/
function job_post_install()  { node_types_rebuild();
$types   = node_type_get_types();
// add the  body field to  the  node type node_add_body_field($types['job_post']);
// Load the  instance definition  for  our  content type's  body
$body_instance = field_info_instance('node', 'body', 'job_post');
// Configure  the  body field
$body_instance['type'] = 'text_summary_or_trimmed';
// Save  our  changes  to  the  body field instance.
field_update_instance($body_instance);
// Create  all the  fields we are  adding  to  our  content type.
foreach   (_job_post_installed_fields() as  $field) { field_create_field($field);
}
// Create  all the  instances for  our  fields.
foreach   (_job_post_installed_instances() as  $instance) {
$instance['entity_type'] = 'node';
$instance['bundle'] = 'job_post'; field_create_instance($instance);
}}
/**
*   Return a  structured array  defining the  fields  created by this  content type.
*   For the  job  post  module there   is only  one  additional field  –  the  company  name
*      Other fields could  be  added by defining them in  this  function as  additional  elements
*   in  the  array  below
*/
function _job_post_installed_fields()  {
$t  = get_t(); return  array('job_post_company' => array( 'field_name'   => 'job_post_company','label' => $t('Company posting the  job  listing'),'type'=> 'text',),);}
/**
*   Return a  structured array  defining the  field  instances associated with  this  content type.
*/
function _job_post_installed_instances()  {
$t  = get_t(); return  array('job_post_company' => array('field_name'   => 'job_post_company', 'type' => 'text', 'label'   => $t('Company posting the  job  listing'), 'widget'=> array('type'=> 'text_textfield',), 'display' => array( 'example_node_list' => array('label'=> $t('Company posting the  job  listing'), 'type' => 'text',),),),);}
/**
*   Implements hook_uninstall().
*/
function job_post_uninstall()  {
// Gather all the  example content that   might  have  been  created while  this
// module was enabled.
$sql   = 'SELECT  nid  FROM   {node}  n WHERE   n.type = :type';
$result = db_query($sql, array(':type'  => 'job_post'));
$nids  = array();
foreach   ($result as  $row)  {
$nids[] = $row->nid;}
// Delete all  the  nodes  at  once node_delete_multiple($nids);
// Loop over  each  of  the  fields  defined by this module and delete
// all  instances of  the  field,  their data, and the  field itself.
foreach   (array_keys(_job_post_installed_fields()) as  $field) { field_delete_field($field);}
// Loop over  any remaining  field  instances attached to  the  job_post
// content type  (such  as  the  body field) and delete them individually.
$instances = field_info_instances('node', 'job_post'); foreach   ($instances as  $instance_name  => $instance) {
field_delete_instance($instance);}
// Delete our  content type node_type_delete('job_post');
// Purge all field infromation field_purge_batch(1000);}

Creating the .info File

Lets also create the job_post.info file and  add  it to the jo post folder.
name = Job Post
description =  job  posting  content type package  = Pro Drupal Development
core  = 7.x
files[] = job_post.install files[] = job_post.module

Creating the .module File

Last, you need the module file itself. Create a file named job_post.module, and  place  it inside sites/all/modules/custom/job_
posting. After you’ve completed the module, you can enable the module on the module listings page (Modules). You begin with
theopening PHP tag and  Doxygen comments.

<?php
/**
*   @file
*   This  module provides a  node type  called job  post
*/
Providing Information About Our Node  Type

Now you’re ready  to add hooks to job_post.module. The first hook  youll want  to implement is hook_node_info(). Drupal
calls this hook  when it’s discovering which node types  are available. You’ll provide some metadata about your custom node.
/**
*   Implements hook_node_info() to  provide  our  job_post type.
*/
function job_post_node_info() { return  array('job_post' => array('name'  => t('Job Post'), 'base' => 'job_post','description' => t('Use this  content type  to  post  a  job.'), 'has_title' => TRUE,'title_label' => t('Job Title'), 'help' => t('Enter the
job  title, job  description, and the  name of  the  company  that   posted  the  job'),),);}

A single module can define multiple node types, so the return value should be an array. Here’s the breakdown of metadata values  
that may be provided in the node_info() hook:

"name": The human-readable name of the node type. Required.
"base": The base  string  used to construct callbacks corresponding to this node type (i.e., if base  is defined as example_foo, then 
example_foo_insert will be called  when inserting a node of that type).  This string is usually the name ofthe module, but not always.Required.

"description": A brief description of the node type. Required.

"help": Help information shown to the user when creating a node of this type. Optional (defaults to '').

"has_title": Boolean indicating whether this node type has a title field. Optional (defaults to TRUE).

"title_label": The label for the title field of this content type. Optional (defaults to Title”).

"locked": Boolean indicating whether the administrator can change the machine name of this type. FALSE = changeable (not locked), TRUE = unchangeable (locked). Optional (defaults to TRUE).

Modifying the Menu Callback


Having  a link on the “Create content” page isn’t necessary for implementing hook_menu(). Drupal will automatically
discover your new content type and  add its entry to the http://example.com/?q=node/add page, as shown in Figure 7-2.
A direct link tothe node submission form will be at http://example. com/?q=node/add/job_post.
The name and  description are taken from the values  you defined in job_post_node_info().


Figure 7-2. The content type appears on the page at http://example.com/node/add. 

If you do not wish to have the direct link added, you could remove it by using  hook_menu_alter(). For example, the following
code  would remove the page for anyone who does not have administer nodes” permission.
/**
*   Implements hook_menu_alter().
*/
function  job_post_menu_alter(&$callbacks) {
// If the  user  does  not  have 'administer nodes'   permission,
// disable the  job_post menu  item  by setting its  access callback to  FALSE.
if (!user_access('administer nodes')) {
$callbacks['node/add/job_post']['access callback'] = FALSE;
// Must unset  access arguments or  Drupal will use  user_access()
// as  a  default access callback.
unset($callbacks['node/add/job_post']['access  arguments']);}}

Defining Node-Type–Specific Permissions with hook_permission()

Typically the permissions for module-defined node types  include the ability to create a node of that type, edit a node you have
created, and  edit any node of that type. These  are defined in hook_ permission() as create  job_post, edit  own job_post, edit any
job_post, and  so on. You’ve yet to define these permissions within your module. Let’s create them now using  hook_permission():

/**
*   Implements hook_permission().
*/
function job_post_permission() { return  array('create job  post' => array('title' => t('Create a  job  post'), 'description'
=> t('Create a job  post'),),'edit own job  post' => array('title' => t('Edit own job  post'),'description' => t('Edit your own job  posting'),),'edit any job  post' => array('title' => t('Edit any job  post'), 'description' => t('Edit any job posting'),),'delete own job  post' => array('title' => t('Delete own job  post'), 'description' => t('Delete own job  posting'),),'delete any job  post' => array('title' => t('Delete any job  post'), 'description' => t('Delete any job  posting'),),);}

Now if you navigate over to People and  click the Permissions tab, the new permissions you defined are there and  ready  to be assigned to user roles.
Limiting Access to a Node  Type with hook  node_access()

You defined permissions in hook_permission(), but how are they enforced? Node  modules can limit access to the node types
they define using hook_node_access(). The superuser (use ID 1) will always bypass any access check, so this hook isn’t called
in that case. If this hook  isn’t defined for your node type, all access checks will fail, so only the superuser and  those with
“administer nodes” permissions will be able to create, edit, or delete content of that type.
/**
*   Implements hook_node_access().
*/
function  job_node_access($op, $node,  $account) {
$is_author = $account->uid == $node->uid; switch   ($op)   {case  'create':
// Allow  if  user's role has  'create  joke' permission.
if (user_access('create job',  $account)) { return  NODE_ACCESS_ALLOW;}
case  'update':
// Allow  if  user's role has  'edit own joke'  permission and user  is
// the  author;   or  if the  user's role has  'edit any joke'  permission.
if (user_access('edit own job',  $account) &&   $is_author || user_access('edit any job',  $account)) {
return  NODE_ACCESS_ALLOW;}
case  'delete':
// Allow  if  user's role has  'delete own joke'  permission and user  is
// the  author;   or  if the  user's role has  'delete any joke'  permission.
if (user_access('delete own job',  $account) &&   $is_author || user_access('delete any job',  $account)) {
return  NODE_ACCESS_ALLOW;
}}}

The preceding function allows users to create a job post  node if their role has the “create job post” permission. They can also
update a job post  if their role has the “edit own job post”  permission and they’re the node author, or if they have the “editany
job post”  permission. Those  with “delete own job post”  permission can delete their own job post, and  those with “delete any jobpost” permission can delete any node of type job  post.

One other $op value that’s  passed into hook_node_access() is view, allowing you to control who views this node. A word of warning, however: hook_node_access() is called  only for single node view pages. hook_node_access() will not preventsomeone from viewing a node when it’s in teaser view, such as a multinode listing page.  You could get creative with other hooks and  manipulate the value of $node->teaser directly to overcome this, but that’s  a little hackish. A better solution is to use
hook_node_grants(), which we’ll discuss shortly.

Customizing the Node  Form  for Our Node  Type
So far, youve got the metadata defined for your new node type and  the access permissions defined. Next, you need to build the node form so that users can enter a job. You do that by implementing hook_form(). Drupal provides a standard node form thatincludes the title, body,  and  any optional fields that you have defined. For the job post  content type, the standard form is more than adequate, so I’ll use it to render the add/edit form.
/**
*   Implement hook_form()  with  the  standard  default  form.
*/
function  job_post_form($node, $form_state)  { return  node_content_form($node, $form_state);}

As the site administrator, if you’ve enabled your module, you can now navigate to Add content -Job Post
and  view the newly created form (see Figure  7-3).


Figure 7-3. The form for submission of a job post

When  you’re working with a node form and  not a generic form, the node module handles validating and  storing all the default
fields it knows  about within the node form (such as the title and  body fields) and  provides you, the developer, with hooks to
validate and  store your custom fields. We’ll cover those next.

Validating Fields with hook_validate()

When  a node of your node type is submitted, your module will be called  via hook_validate(). Thus, when the user submits the
form to create or edit a job post, the invocation of hook_validate() will look for the function job_post_validate() so that you can
validate the input in your custom field(s). You can make changes to the data after submission—see form_set_value(). Errors  should be set with form_set_error(), as follows:
/**
*   Implements hook_validate().
*/
function job_post_validate($node) {
// Enforce  a  minimum  character count  of  2  on company  names.
if (isset($node->job_post_company) && strlen($node->job_post_company['und'][0]['value']) < 2) { form_set_error('job_post_company',t('The  company  name is too  short. It must be  atleast characters.'),}}
$limit_validation_errors = NULL);

Notice that you already defined a minimum word count for the body field in hook_node_info(), and Drupal will validate that for you automatically. However, the punchline field is an extra field you added to the node type form, so you are responsible for
validating (and loading and  saving)  it.

Saving Our Data with hook_insert()

When  a new node is saved, hook_insert() is called.  This is the place  to handle any custom processing of the node’s content before the node is saved. This hook  is called  only for the module that is defined in the node type metadata. This information is defined in
the base key of hook_node_info() (see the “Providing Information About Our Node  Type section). For example, if the base keyis job_post, thejob_post_insert() is called.  If you enabled the book module and  created a new node of type book,job_post_
insert() would not be called; book_insert() would be called  instead because book.module defines its node type with a base key ofbookHeres the hook_insert() function for job_post.module. I’ll create a log entry in the watchdog table every time  a new job
posting node is created.
/**
*   Implements  hook_insert().
*/
function  job_post_insert($node)  {
// log  details  of  the  job  posting  to  watchdog watchdog('job  post',  'A  new  job  post  titled:  '.$node->title.'  for  company:  '.$node->job_post_company['und'][0]['value'].' was  added by UID:  '.$node->uid,  $variables  = array(), WATCHDOG_NOTICE,  $link  = 'node/'.$node->nid);}

Keeping Data Current with hook_update()

The update() hook is called  when a node has been edited and  the core node data has already been written to the database. This is
the plac to write database updates for related tables. Like hook_insert(), this hook is called  only for the current node type. For
example, if the node type’s module key in hook_node_info() is job_post, then job_post_update() is called.
/**
*   Implements  hook_update().
*/
function  job_post_update($node)  {
// log  details  of  the  job  posting  to  watchdog
watchdog('job  post',  'A  job  post  titled:  '.$node->title.'  for  company:  '.
$node->job_post_company['und'][0]['value'].
' was  updated  by UID:  '.$node->uid,  $variables  = array(), WATCHDOG_NOTICE,  $link  = 'node/'.$node->nid);}

Cleaning Up with hook_delete()

Just after a node is deleted from the database, Drupal lets modules know what  has happened via hook_delete(). This hook  is typically used to delete related information from the database. This hook  is called  only for the current node type being deleted. If the
node type’s base key in hook_node_info() is job_post, then job_post_delete() is called.
/**
*   Implements  hook_delete().
*/
function  job_post_delete($node)  {
// log  details  of  the  job  posting  to  watchdog
watchdog('job  post',  'A  job  post  titled:  '.$node->title.'  for  company:  '.
$node->job_post_company['und'][0]['value'].
' was  deleted  by UID:  '.$node->uid,  $variables  = array(), WATCHDOG_NOTICE,  $link  = 'node/'.$node->nid);}

Modifying Nodes of Our Type with hook_load()

Another hook  you need for your job_post module is the ability to add custom node attributes into the node object as it’s
constructed. We need to inject the job post  sponsor into the node loading process so it’s available to other modules and  the theme layer.For that you use hook_load()This hook is called  just after the core node object has been built  and  is called  only for the
current node type being loaded. If the node type’s module key in hook_node_info() is job_post, then job_post_load() is called.  In
the example, I will insert anode attribute called  sponsor and  will assign a value that can then be used else where.
/**
*   Implements hook_load().
*/
function  job_post_load($nodes) {
// Add  a  new element  to  the  node at  load  time  for  storing the
// job  posting sponsor  information foreach   ($nodes  as  $node)  {
$node->sponsor  = "ACME  Career  Services, Your Source  for  Drupal Jobs";
}
return  $node;}

Using hook_view()

Now you have a complete system to enter and  edit job posts. However, your sponsors will be frustrated, because although sponsor
information has been added previously through hook_load, you havent provided a way for the sponsor information to be displayed when viewing a job post.  I’ll do that now with hook_view():
/**
*   Implement hook_view().
*/
function  job_post_view($node, $view_mode) {
// Add  and theme the  sponsor  so  it appears  when the  job  post  is displayed if ($view_mode == 'full')  {
$node->content['sponsor'] = array(
'#markup' => theme('sponsor', array('sponsor'  => $node->sponsor, ‘sponsor_id’ => $node_nid)),'#weight' => 100,);}
return  $node;}

I’ve broken the formatting of the sponsor into a separate theme function so that it can be easily overridden. This is a courtesy to the overworked system administrators who will be using your module but who want  to customize the look and  feel of theoutput. To 
enable this capability, I’ll create hook_theme() function that defines how the module will handle theming the new sponsor field. In
the hook_theme function, Ill define the variables associated with the sponsor field and  the template file that will benused to define
how the sponsor information will be rendered as part  of the node.
/**
*   Implements hook_theme().
*/
function  job_post_theme() {
// define the  variables and template   associated with  the  sponsor  field
// The sponsor  will  contain the  name of  the  sponsor  and the  sponsor_id
// will be  used  to  create a  unique  CSS  ID
return  array('sponsor' => array('variables' => array('sponsor' => NULL,  'sponsor_id' => NULL), 'template' =>'sponsor',),);}

The last step  in the process is to create the template file for displaying sponsor information. In the hook_theme() function, I assigned the value sponsor to the template file attribute—so I’ll need to create sponsor.tpl.php file in my module directory.
The contentof that file is as follows:
<?php
/**
*   @file
*   Default theme implementation   for  rendering   job  post  sponsor  information
*
*   Available variables:
*   - $sponsor_id: the  node ID asociated with  the  job  posting
*   - $sponsor:           the  name of  the  job  post  sponsor
*/
?>
<div  id="sponsor-<?php  print  $sponsor_id ?>" class="sponsor">
<div  class="sponsor-title">
<h2>Sponsored by</h2>
</div>
<div  class="sponsored-by-message">
This  job  posting was sponsored  by:  <?php print $sponsor;   ?>
</div>
</div>

You will need to clear the cached theme registry so that Drupal will look at your theme hook.  You can clear the cache using devel.module or by simply  visitin the Modules page.  You should now have fully functioning job post  entry and  viewingsystem. Go ahead and  enter some job posts and  try things out. You should see your job post  in a plain and  simple format, as in
Figures 7-4 and  7-5.


Figure 7-4. Simple theme of job post node


Figure 7-5. The sponsor  is not added when the node is shown in teaser view.


Manipulating Nodes That Are Not Our Type with hook_node_xxxxx()

The preceding hooks are invoked only based on the base  key of the module’s hook_node_info() implementation. When  Drupal
sees a blog node type, blog_load() is called.  What if you want  to add some information to every node, regardless of its type?The hooks we’ve reviewed so far aren’t going to cut it; for that, we need an exceptionally powerful set of hooks.

The node_xxxx hooks create an opportunity for modules to react to the different operations during the life cycle of any node. The node_xxxx hooks are usually called  by node.module just after the node- type–specific callback is invoked. Here’s a list of the
primary node_xxxx hook  functions:

hook_node_insert($node): Responds to creation of a new node.
hook_node_load($node, $types): Acts on nodes being loaded from the database. $nodes is a keyed array of nodes being loaded
where the key is the node ID,  $types is an array of node types  being loaded.
hook_node_update($node): Responds to updates to a node. hook_node_delete($node): Responds to node deletion. hook_node_view$node, $view_mode): Acts on a node that is being rendered where $view_mode defines what  mode the node is being displayed in—e.g., full or teaser.
hook_node_prepare($node): Acts on a node that is about to be shown in the add/edit form.
hook_node_presave($node): Acts on a node that is being inserted or updated.

hook_node_access($node, $op,  $account): Controls access to a node where $op is the type of operation being performed (e.g.,
insert, update, view, delete) and $account is the user  account of the person performing the operation.
hook_node_grants_alter(&$grants, $account, $op): Alters user access grants when trying to view, edit, or delete a node.

The order in which hooks are fired when displaying a node page such as http://example.com/?q=node/3 is shown in Figure  7-6.

Figure 7-6. Path of execution for displaying a node page

How Nodes Are Stored


Nodes live in the database as separate parts. The node table contains most of the metadata describing the node. The node_revisions table  contains the node’s body and  teaser, alon with revision-specific information. And as you’ve seen in the
job_post.module example, other nodes are free to add data to the node at node load time  and  store whatever data they want  in their own tables. A node object containing the most common attributes is pictured in Figur 7-7. Note that the table
created by the field API to store the job post  company is separate from the main node table. Dependinon which other
modules are enabled, the node objects in your Drupal installation might contain more ofewer properties.





Không có nhận xét nào:

Đăng nhận xét