Upload
nessinen
View
30
Download
1
Tags:
Embed Size (px)
DESCRIPTION
Drupal guide
Citation preview
How To Store Custom Data In Drupal 7
DrupalCamp Utah 2013August 2, 2013
Walt [email protected]
http://drupal.org/user/156317 I
"I screw up so you don't have to"
How To Store Custom Data In Drupal 7by Walt Haas is licensed under a
Creative Commons Attribution-ShareAlike 3.0 Unported License.
The use case
You have a special type of data to store in Drupal. You need to figure out the best way to do this. This talk assumes that you already know how to install an existing module.
The talk attempts to show what you can do with existing modules. If you need to create a custom module, there are some examples of code you need to write.
Drupal is free software
Drupal is released under the GNU General Public License verson 2. This guarantees that Drupal is Free as in Freedom. Among the four software freedoms guaranteed to you by the GPLv2 are the freedom to study how the program works and the freedom to improve it.
This talk will support you in exercising these freedoms by showing examples of controlling Drupal through both the browser and PHP code.
If you want to use Drupal only through the browser, you may ignore the code examples.
Tips for learning
Start with a Minimal install profile not the default Standard profile. The Minimal profile makes it clearer where each piece of the puzzle comes from.
To get visibility of how the database works, use MySQL and phpMyAdmin.
To understand how the PHP code works, it helps to have an IDE with interactive debugging. Netbeans with Apache and Xdebug works well for this.
The Devel module and Drush have many useful tools.
Installing the examples
The examples for this talk can be installed from the author's sandbox on git.dupal.org by using git. In your modules directory (something like files/sites/all/modules/) do this :
git clone --branch master \ http://git.drupal.org/sandbox/WaltHaas/2048391.git \ data_storage_examples
Drupal core data storage
Drupal core with no optional modules enabled stores data in nodes. A node can be created independently of everything except the user that creates it.
Nodes are described by the type of content they hold. Each node has a content type.
We will use data about a collection of Drupal books as our example, progressing from the simplest to the most powerful way to manage this data.
Allow limited HTML in plain text
To display lists properly change the Plain text input formatAdministration » Configuration » Content authoring » Text formats
Content type creation
Start with a minimal installation. Log in as user 1. There are no content types:Administration » Structure
Create a new content type
Click on Add content type to create your first content type. Give it a name and let everything else default. Click Save content type:Administration » Structure » Content type
Content type permissions
Going to url/admin/people/permissions we see that there are now permissions available to control access to our new content typeAdministration » People
Create content of the new type
Now we can go to url/node/add/book1 to create content of type Book1. Give the content a Title and some Body text, then click Save to save this content:Add content
View the content we created
Our content looks like this:
We have both View and Edit permission. The submitting user and submission timestamp are both shown.
Edit the content we created
By clicking the Edit tab, we have the opportunity to edit the content:
Content revision and publication
On the Edit tab for our content page we see a way to track revisions to the content.
Revise the content
Let's change a line in the book description:
Preview the change
Click the Preview button at the bottom. At the top of the new page we see:
Actually, that delimiter only works if you go to the Text formats page and add <!-- --> to the list of allowed HTML tags.
Save the revision
At the bottom of the Edit tab, check Create new revision, add a log message and click Save
Revisions tab appears
When we look at our content again, we see a new tab Revisions
See revision history
By clicking the Revisions tab, we see the log messages and authors:
Install the Diff module to see what changed
If we install the Diff module we can compare two versions:
Diff compare shows the changes
Compare highlights the additions, deletions and changes as in a software version control system:
Notice the red period at end of line on right
What did we just do in the DB?Add content type
Add content type adds a row to the {node_type} table:
What did we just do in the DB?Add content
Add content adds rows to the {node} and {node_revision} tables:
What did we just do in the DB?Create new revision
Create new revision adds a row to the {node_revision} table and updates the node's row of the {node} table:
What did we just do in the DB?Where did the text go?!
The text is not stored in the node directly. Instead, it is stored in a storage area called a field. When we created the Book1 content type, we automatically created a Body field for the content type. Add content adds a row to the {field_data_body} and {field_revision_body} tables:
What did we just do in the DB?Where did the text revision go?
Create new revision adds a row to the {field_revision_body} table and updates the node's row of the {field_data_body} table.
What did we just do in the DB?Added Drupal variables
We added some rows to the {variable} table
Create a content type in a module
This goes in the modulename.install file:
function modulename_install() { // Create the book1 node type $book1 = array(
'type' => 'book1','name' => t('Book1'),'base' => 'node_content','description' => t('Content type to hold a book description'),'has_title' => TRUE,'custom' => FALSE,
); $book1_type = node_type_set_defaults($book1); node_add_body_field($book1_type); node_type_save($book1_type);}
Properties of a node
Every node has the following properties:● Node ID● Version ID● Content type● Language● Title● Node owner user ID● Published? (true/false)● Creation timestamp● Last changed timestamp● Comments allowed? (true/false)● Promoted to front page? (true/false)● Sticky at top of lists? (true/false)● Translation set ID● Translation update necessary? (true/false)
Other properties can be added as fields, as shown later.
Review Drupal core data storage
Let's review what we just did. Drupal 7 core stores data in nodes. Nodes always have a content type. We added a content type and stored a node of that type with a title and some text.
The example showed how to define a content type with the browser or by implementing hook_install() in a module.
Looking at our data
Storing data is useless unless there is a way to find what you want in the stored data. The most popular way to do this in Drupal is with the Views module. You will also need the Chaos tool suite module that Views uses.
Enable the Chaos tools, Views and Views UI modules for the next step.
We also need more books in the database to make the example meaningful. The Bookshelf Example 1 module installs a dozen assorted books to work with.
Create a bookshelf view
With Views UI enabled we can create a bookshelf view:
Administration » Structure
Click Add new view
Name the new view
Give the view a name and select content type Book1
Click Continue & edit
View details
The top part of this page selects data and controls how it will be presented. Note that any changes you make are not saved until you click the Save button.
View auto preview
For the moment, scroll down the page to the Auto preview checkbox and look at the text below. This is a preview of what the user will see. By default it shows title, user that posted the content and the summary section of the node.
View auto preview continued
When you change the control parameters in the top section of the page this preview section will be automatically updated to show you what the view will look like with the new parameters.
You can experiment freely and see the results immediately. Your changes will not affect the publicly visible view until you click the Save button at the top.
Change view format
Let's try a different format. In the middle of the page is a Page details box. In the left column, find Format: Unformatted list and click on it. A modal window appears:
Select table format
In the modal window, check the Table box then click Apply (all displays). The Page: Style options modal window appears. Click Apply (all displays) again. The main window for the view reappears. The Auto preview section has been updated and now shows the new format, which is the book title with a link to the node:
Select fields to show
In the Page details section, below Format we now see
The table format allows us to select which part of the content will appear in the view. Click on Add in the button just to the right of Fields
Add a field to the view
A modal window appears with a list of content items we may add to the table. Title with link are already part of the table but, confusingly, aren't checked. Scroll down the list to Content: Post date and check the box next to that.
Click Apply (all displays)
Select format of this field
Another modal window appears. Scroll down to the selector labeled Date format and choose Short format.
Click Apply (all displays)
Preview now shows date
The auto preview section now shows the content Post date in a new column:
We will see that how we store data in a content type controls what data is available to be shown in a view, an important consideration.
Add a filter to the view
A filter allows us to select which books will appear in the view based on some criterion we choose. In the Page details section, below Fields find Filter criteria. Click on Add in the button just to the right of Filter criteria
Select filter field
A modal window Add filter criteria appears. Find the line with Content: Body (body) and check the box next to it.
Click Apply (all displays)
Configure filter criterion
Another modal window appears allowing us to configure the filter criterion. Check the box next to Expose this filter to visitors
Allow viewers to set filter
Near the bottom of the modal window select Operator Contains and check Expose operator and Remember the last selection
Click Apply (all displays)
Check operation of filter
The Auto preview section of the view now has a tool to choose books. If we specify theme and click Apply we get a list of only those nodes with the word "theme" in the body of the node. Available content filter criteria is another important design consideration.
Save the view
Our view is not yet permanent. Near the top of the Page settings section, in the center, notice Path: /bookshelf1
Click the Save button in the upper right to save the view.
Now we can go to url/bookshelf1 to use the view
Review: importance of Views
The Views module is one of the most popular Drupal modules because of its abililty to select and display data.
What the Views module can do with your data depends heavily on exactly how you store it.
Therefore, as you develop your data storage scheme, check your decisions by testing how they work with Views.
Useful contributed modules 1
An advantage of using a content type to store your data is that a large number of contributed modules work with content types. A partial list:● Address Field● Backup and migrate● Calendar A view that works with a content type that has a Date field● CAPTCHA Works on a form, such as the comment form on a content type● Chaos tool suite (ctools)● Computed Field● Content Glider● Content Migrate Converts Drupal 6 CCK fields to Drupal 7 fields● Content Taxonomy● Context● Custom Contextual Links● Date
Useful contributed modules 2
● Delta● Deployment● Devel● Diff● Display Suite● DraggableViews● Dynamic display block● Email Field● Entity API● Entity Dependency API You must write PHP code to describe any entity
dependencies of your content type beyond the core entities and entity reference fields.
● Entity reference● Features● Feeds May require custom mapper for target fields● Field collection
Useful contributed modules 3
● Field group● FileField Sources● Field Permissions● Fivestar● Flag● Geocoder● Geofield● Geolocation● Global Redirect● Google Analytics● Invisimail● Is Useful● Link● Location● Menu block● Menu Breadcrumb
Useful contributed modules 4
● Menu position● Metatag● Migrate You need to add Migrate code for each content type and field
you define● Mollom Works on a form, such as the comment form on a content type● Node clone● Nodequeue● Options Element● Page Title● Panels● Pathauto● Pathologic● Plus 1● Print● Radioactivity● Rate
Useful contributed modules 5
● reCAPTCHA Works on a form, such as the comment form on a content type
● Redirect● References Use the Entity reference module instead● RESTful Web Services● Revisioning● Scheduler● Search configuration● Search Restrict● Services To control access to specific fields you may need to implement a
hook● SpamSpan filter works, but Invisimail looks better● TagClouds● User Points● Univerally Unique IDentifier
Useful contributed modules 6
● Views When Views UI is enabled, custom content types are listed as candidates for display
● Voting API● Workbench● XML sitemap
Drupal 7 stores user data in entities and fields. These are abstract concepts. So far we have worked with one kind of entity, Node, and one kind of field, Body.
The entity abstraction was introduced in Drupal 7. In earlier versions of Drupal, Nodes, Users and Files were independent. In Drupal 7, these are all instances of the entity abstraction.
How Drupal 7 stores data
Views shows entities
On the Add new view page, the first selector shows a list of the entities (among other things) that can be used as the basis of a view.
This entity determines what data the view will be able to find. For example, if we choose Content we can only access Users that have created Content nodes.
Add a few entities
Enable the Comment and Taxonomy modules to define additional entities. Now the Add new view page lists the additional entities in the first selector
Entity construction kit
You can define new entity types through the browser by installing the Entity Construction Kit (ECK) module. Entity types defined this way are available to views.
Defining an entity in a module
Any module can define an entity by implementing hook_entity_info(). You can use the DrupalDefaultEntityController class or define a controller class that implements the DrupalEntityControllerInterface. These are defined in files/includes/entity.inc where you can see the functions common to all entities. By using one of these you have access to a variety of common entity functions.There are only a few entity functions in Drupal 7 core. Additional entity functions are available in the Entity API module.
Fields
In Drupal 7 a field is a piece of storage attached to an entity. The code for this is found in Drupal core in files/modules/fields/
CAUTION!The terminology used for this is very confused. Drupal documentation frequently applies the word "field" to a column in a database table. A field constructed by the field module is stored in a table with seven columns of bookkeeping data in addition to the columns that store the data you want. Which meaning is intended is not always clear from context! This talk tries to keep a clear distinction between field and column.
Extra fields
MORE CONFUSION!
The documentation further confuses things by giving the name “extra fields” to columns like the title column in a node that aren’t fields in the Drupal 7 sense.
The motivation for this confusing terminology seems to be that you reference these columns in Views and elsewhere as if they were fields.
Sometimes they’re called “pseudo fields”
Body field is optional
When you create a content type, a body field is added by default. You can delete the body field if you want. The node title is a column in the node table and cannot be deleted.
You can add fields to a content type as shown in the next section.
Field types
Each field holds data of some defined type, known as the field type. In a minimal install, the Field, Field SQL storage and Text modules are enabled, because they are required by Drupal core. The Text module defines fields of character string types.
You can add fields to any fieldable entity. These include Comment, Node, Taxonomy term, User, and any other entity defined with 'fieldable' => TRUE
Add a field to a content type
To add fields to entities with a browser, you need to enable the Field UI module. With this module enabled, you can control the fields attached to Book1 atAdministration » Structure » Content types » Book1
Add a field to the user entity
With the Field UI module enabled, you can control the fields attached to the User entity atAdministration » Configuration » People » Account settings
Basic field types
The basic field types are defined in the various modules in files/modules/field/modules/. The “Select a field type” pulldown will always offer at least the field types defined by the Text module, which are: Long text, Long text with summary and Text. If you are learning how to write a module that defines a field type, these fields are defined in files/modules/field/modules/text/text.module:text_field_info() and are a good example.
Number field types
If you enable the Number module the field type pulldown will offer three more field types: Decimal, Float and Integer. These are defined in files/modules/field/modules/number/number.module:number_field_info()
Fields vs. field types
It's important to be clear on the distinction between field and field type.
A field type is a general type of information such as integer, float, character string etc. Field types can only be defined by a module.
You create a field by assigning a name to a field type. For example, you could create First Name and Last Name fields of field type Text. You can use the Field UI to create a field of an existing field type.
Create two fields of same field type, add them to User entity
Use Add new field to add two different fields of the same field type to the User entity
The new field is now available to other fieldable entities
Administration » Structure » Content types » Book1
Field bundles
A bundle is the collection of fields attached to some entity type. Core defines a bundle for every node type, for comments on each node type, for taxonomy terms (for each vocabulary), and one for user, aptly named 'user'.
The rows in {field_data_...} tables contain bundle names in the bundle column. For example
Field instances
A field instance is the way a field is tailored for use with a particular bundle. Our example First Name field is bundled with the User entity and the Book1 content type, so we can show it to the viewer in different ways. For example on the Book1 content type we might label the First Name field as Author First Name and require it:
Field instances continued
When the same First Name field is bundled with the User entity we can give it a different label and make it optional
Configuration information for instances is stored in the {field_config_instance} table in a BLOB
Create a field in PHP code
If the field type already exists, creating a field takes about 35 lines of code. Download the examples and look in file
data_storage_examples_bookshelf2.install
for function
_data_storage_examples_bookshelf2_attach_field()
Widgets and formatters
Every field has a widget and a formatter.
A widget is a means for a user to enter data through their browser. The form of widget depends on the field type of the field. Some field types offer more than one widget. When you add a new field, you select the widget for it. The help text says Form element to edit the data
A formatter is a way to present the data to a browser user. The formatter also depends on the field type of the field. You select the format and labels for the field on the Manage display tab.
Fields vs. columns
We have seen how to create and use a Drupal 7 field. Inside the database the value of a field is stored in a table with eight or more columns. Seven columns are used for bookkeeping information about the field value. If we add a field of integer type called "Logins" to the user entity we create {field_data_field_logins}and {field_revision_field_logsins} tables in the DB:
Multi-value fields
A field type can be defined to hold more than one value. The number of values allowed by a field type is called the cardinality of the field type. Cardinality can be a certain number or "unlimited" (4294967295).
If you enable the List core module, four new field types are available: Boolean, List(float), List(integer), List(text). You define a set of key|value pairs that can be assigned to the field. Only the listed values are eligible to be stored in the field. Let's add a list of ice cream flavors to the user entity:
Add a List(text) field to User
We add a multi-value field listing the flavors the user likes to the User entity
List the available flavors
On the Field settings tab for the Likes flavors field, list the allowed values. If we don't list a key, the value will be used as the key.
Set the list number of values
Allow the user to select any number of flavors
Edit flavor preference(s) of a user
Edit any user. On the Edit tab we now see a list labeled Likes flavors with a check box for each allowed flavor value. Check the user's prefered flavors and click Save.
View Likes flavors field for a user
View the user and see their flavor preference(s) listed
Likes flavors field in the database
By creating the Likes flavors field, we added tables {field_data_likes_flavors} and {field_revision_likes_flavors} to the database
Think of the value of "Likes flavors" as an array. The delta column is the array index for the values in the field_likes_flavor_values column.
Some contributed modules that define useful field types
● Address Field● Date● Email Field● Entity reference● Field collection● Fivestar● Geofield● Geolocation● Is Useful● Link● Location● Radioactivity
Review of fields and entities
Entities are a new concept in Drupal 7.
Nodes and users are both entities.
Entities exist (mostly) independently.
Some entities are fieldable, meaning you can attach a field to them. Nodes and users are both fieldable.
Fields depend on the entity they are attached to.
Fields can be created by the Field UI module from an existing field type. Field types are created by modules.
Book2 content type
In the Book1 content type we had only a Body field. Information about author(s), publisher and the URL of the book description were lines in the body field. Unfortunately, the only way to use Views to find a book is to search the body text.
If we list Author(s) and Publishers in separate fields we can have Views search them specifically, so let's define a Book2 content type that puts this information in different fields.
We install the Date and Link modules to define field types
Book2 field definitions
We define separate fields for Author(s), Publisher, Publication date, ISBN and a link to the publisher’s description of the book
Book2 multiple authors
Publisher’s description is a URL. The field is configured to use the field label as title. Author(s) is a multi-value text field. Unlimited authors can be added.
Book2 publication fields
Publication date is a field. Publisher and ISBN are text fields.
Bookshelf2 view
We create a view that allows filtering on several fields. The column headers can be clicked to sort the rows on the respective column.
Bookshelf2 view is default
When you install the Bookshelf2 example module, this view is installed automatically, along with the data for a dozen books.
Access the view at url/bookshelf2
Enable the Views UI module and edit this view to see how the fields and filters are set up. The clickable column headers are set in Format: Settings and only work when there are no Sort criteria specified.
Custom entity facilities
Support for entities does not include revision managment. If you want revision support for your custom entity you need to write it yourself. For an example of how to do this see the User Revision contributed module.
Entity support in Drupal core is limited. The Entity API module provides additional useful functions.
Modules that define entity types
These contributed modules define entity types● Drupal Commerce● Field collection● Location location_entity submodule● Ubercart
In some cases it isn't clear why this decision was made instead of using a content type.
Direct database API calls
Modules can make calls directly to the database API. In fact, most do. Some things can't be accomplished through fields and entities.
Don’t make this choice unless you understand what you are giving up! Before you code direct database API calls, make sure that there isn't a way in the Entity API or Field API to reach your goal.
Junction tables
One goal that generally requires direct DB API calls is constructing a many-to-many junction table.
Examples of this in Drupal core are the {users_roles} and {taxonomy_index} tables. The {taxonomy_index} table matches taxonomy term entities with the tagged entity.
An example in a contributed module is the Flag module, which defines flags and maintains a junction table matching flags to entities. The flags aren't entities or fields, but the targets of the junction table are entities.