Creating New Tables and GalleryStorage

alexisb
alexisb's picture

Joined: 2005-11-24
Posts: 56
Posted: Mon, 2006-01-23 02:56

Hello, I'm a little confused with how to create new tables in the database.

I am coding a custom module and would like to have a table where some related data would be stored.

I've studied other modules and would like to use comment module for asking some questions.

I've seen this directory for comment:

modules/comment/classes/GalleryStorage

There are other directories inside: DatabaseStorage, schema, platform, xml-src and some .sql files for different DBMS.

The file corresponding to MySQL have some kind of pseudo SQL like this:


    -- This file was automatically generated from an XSL template, which is
    -- why it looks so ugly.  Editing it by hand would be a bad idea.
    --

    CREATE TABLE DB_TABLE_PREFIXComment (
  DB_COLUMN_PREFIXid
      int(11)
    
    NOT NULL
  
      ,
    DB_COLUMN_PREFIXcommenterId
      int(11)
    
    NOT NULL
  
      ,
    DB_COLUMN_PREFIXhost
      varchar(
      
          128
        
      )
    
    NOT NULL
  
      ,
    DB_COLUMN_PREFIXsubject
      varchar(
      
          128
        
      )
    
      ,
    DB_COLUMN_PREFIXcomment
      text
    
      ,
    DB_COLUMN_PREFIXdate
      int(11)
    
    NOT NULL
  
    , 
  
      PRIMARY KEY (DB_COLUMN_PREFIXid)
    
    , 
  
    INDEX (DB_COLUMN_PREFIXdate)
    

    ) TYPE=DB_TABLE_TYPE;

    INSERT INTO DB_TABLE_PREFIXSchema (
      DB_COLUMN_PREFIXname,
      DB_COLUMN_PREFIXmajor,
      DB_COLUMN_PREFIXminor
      ) VALUES (
      'Comment',
      1,
      0
      );

Is it needed that I use something like this if I want to create my own MySQL tables for my custom modules?, if so I would like to know how to create these files (or where to read more to understand what you are doing here, and why :) ).

Another doubt I have is how the actual database operations are called from a module, insert.update, delete, select. I see there is a class GalleryStorage but in all the comment module code I just see one reference to a $storage object in GalleryCommentSearch.class:

$storage =& $gallery->getStorage();

which I see it's using a method from Gallery.class which actually creates a GalleryStorage object:

    function &getStorage() {
	if (!isset($this->_storage)) {
	    GalleryCoreApi::relativeRequireOnce('modules/core/classes/GalleryStorage.class');
	    GalleryCoreApi::relativeRequireOnce('modules/core/classes/GallerySearchResults.class');
	    $this->_storage = new GalleryStorage();
	}

	return $this->_storage;
    }

I think I'm almost there but I need to "connect the dots" to completely understand the logic of the application, any directions you could give me will be greatly appreciated.

Regards!

Alexis Bellido - Ventanazul web solutions

 
valiant

Joined: 2003-01-04
Posts: 32509
Posted: Mon, 2006-01-23 19:12

as explained in http://gallery.menalto.com/node/36885#comment-134279 there are two types of database tables in g2:
- Entities:
an entity is just a general term for an object. an item is an entity, a comment is an entity, a user is an entity, ...
- Maps:
with a map table you can map values / settings to other values. e.g. we use the itemAttributesMap to map the view count to itemIds. each item in g2 has a view count (how many times visitors have viewed this item). so we need a map table with 2 columns (at least): 1. itemId, 2. viewCount. then you can have an (map) entry in this table for each item & view count pair.

how to define / add new tables?
first, get the latest nightly snapshot since a lot has changed since G2.0.

- Maps:
define Maps ins modules/yourmodule/classes/Maps.xml and then run gmake in modules/yourmodule/classes/ . gmake will create the CREATE TABLE SQL code in modules/yourmodule/classes/GalleryStorage/schema.tpl .
- Entities:
create a class with your entity's name in modules/yourmodule/classes/ , e.g. modules/yourmodule/classes/GalleryAudioItem.class . in this class, use XML to describe your class members (the stuff above the class GalleryAudioItem { line:

/**
 * ....
 *
 * @g2 <class-name>GalleryAudioItem</class-name>
 * @g2 <parent-class-name>GalleryDataItem</parent-class-name>
 * @g2 <schema>
 * @g2   <schema-major>1</schema-major>
 * @g2   <schema-minor>0</schema-minor>
 * @g2 </schema>
 * @g2 <requires-id/>
 *
 * @package Audio
 * @subpackage Classes
 */

of course you need to decide what parent class matches best your class's needs.
and for each class member, add XML too, e.g.

    /**
     * the name of the track
     *
     * @g2 <member>
     * @g2   <member-name>trackName</member-name>
     * @g2   <member-type>STRING</member-type>
     * @g2   <member-size>LARGE</member-size>
     * @g2   <required/>
     * @g2 </member>
     *
     * @var string $trackName
     * @access public
     */
    var $trackName;

etc.
finally, run gmake in modules/yourmodule/classes/ and it will generate the CREATE TABLE SQL code for you.

the list of all allowed column data types isn't documented yet.
there are no double precision / floats, only INTEGER, there's STRING from small to long and additionally there's TEXT for very long textual data. etc.
you need to set required / primary / you can define multi-column indices etc.
just look at existing modules to see what is possible.

what else is needed?
- Maps:
for maps, this is all. if the module is new, the create table code is automatically executed on module installation.
if the module isn't new, you need to increment the module's version number. during the upgrade, the map table will automatically created.

- Entities:
you need to register the entity in your module.inc file. see modules/comment/module.inc on how it registers its GalleryComment.class entity
the table itself is created automatically just like it is done for maps.

changing table definitions:
============================
you can change table definitions too. you need to change the table schema number (e.g. from major/minor 1, 0 to major / minor 1, 1.
for maps, change the XML in Maps.xml. this will make sure all users that install this module from scratch get the new table definition.
for tables, do the same, change your class.
additionally, you need to create a change definition in modules/yourmodule/classes/GalleryStorage/xml-src/
if you need to alter a table, the file you create there should be called A_GalleryAudioItem_1.0.xml (a for alter, 1.0 for the old schema major/minor version ).
if you need to drop a table, call it R_...
see modules/comment/classes/GalleryStorage/xml-src and modules/core/classes/GalleryStorage/xml-src for a few examples.
once you're done with adding the change file and changing the Maps.xml / class file, run gmake in modules/yourmodule/classes/ and it will generate the CREATE and ALTER table statements.

increment the module version and in your module's upgrade() function, you must call
$storage =& $gallery->getStorage();
$ret = $storage->configureStore($this->getId(), array('GalleryAudioItem:1.0'));
to trigger the execution of the alter table code for GalleryAudioItem in version 1,0.

 
alexisb
alexisb's picture

Joined: 2005-11-24
Posts: 56
Posted: Wed, 2006-01-25 20:21

Wow, thanks Valiant, that needed to be said :) , I will continue my work with G2.1 and keep learning so I can help later with the documentation project.

Regards.

Alexis Bellido - Ventanazul web solutions

 
alexisb
alexisb's picture

Joined: 2005-11-24
Posts: 56
Posted: Wed, 2006-01-25 20:37

Oh, one more thing, what about the regular db operations?, insert, update, select, delete. How do I call them from my module code?

Regards!

Alexis Bellido - Ventanazul web solutions

 
valiant

Joined: 2003-01-04
Posts: 32509
Posted: Thu, 2006-01-26 21:49

- Insert:
maps: use GalleryCoreApi::addMapEntry() to insert 1 or more rows
entities: use GalleryCoreApi::newFactoryInstance and similar methods to get an instance, then call $entity->create(); set a few attributes with $entity->setColor('red'); or something like that and finally call $entitiy->save();
- Update:
maps: use GalleryCoreApi::updateMapEntry()
entities: $entity->save();
- Delete:
maps: GalleryCoreApi::removeMapEntry() or GalleryCoreApi::removeAllMapEntries();
entities: GalleryCoreApi::deleteEntityById() or $entity->delete();
- Select / free form queries:
entities: GalleryCoreApi::loadEntitiesById() or free form sql to get ids and then load with loadEntitiesById()
maps: $gallery->search($query, $data, $options); always use ? as a placeholder for actual values and all values should go into $data. the query language is a DMBS-independent, abstracted SQL
e.g. SELECT g_id, g_title FROM g2_Item WHERE g_summary = 'at the beach'; should be
$query = 'SELECT [GalleryItem::id], [GalleryItem::title] FROM [GalleryItem] WHERE [GalleryItem::summary] = ?';
$data = array('at the beach');
list ($ret , $results) = $gallery->search($query, $data);
reasons:
- by "binding" parameters in the db abstraction layer we make sure there are no db injections vulnerabilities in G2
- by using [GalleryItem] and [GalleryItem::id] instead of the actual database table / column names we can add the table / column prefix independently and we could do other parsing
- if you need things as string concatenation or other DBMS specific SQL, use $storage->getFunctionSql()

hint:
if you need to use $gallery->search(), make sure your parameter values in $data are all correctly typed. they need to match the db column type. e.g. (int) for integer columns and (stirng) for varchar / text columns.

 
alexisb
alexisb's picture

Joined: 2005-11-24
Posts: 56
Posted: Thu, 2006-01-26 21:57

Thanks a lot Valiant.

Alexis Bellido - Ventanazul web solutions

 
mindless
mindless's picture

Joined: 2004-01-04
Posts: 8601
Posted: Sat, 2006-02-04 19:30

new entity.. after create() you still need to do save()

 
valiant

Joined: 2003-01-04
Posts: 32509
Posted: Sat, 2006-02-04 19:53

thanks, updated.

 
nospamisgoodspam

Joined: 2005-08-31
Posts: 40
Posted: Mon, 2006-04-03 01:17

So now with gallery 2.1 I don't need to run gmake or have any GNUmakefiles to generate the required tables and inc files to accompany my class files?

This is all done automagically now?, and if I add

$storage =& $gallery->getStorage();
$ret = $storage->configureStore($this->getId(), array('MyModuleItem:1.0'));

to the upgrade portion in my module.inc, these will get rebuilt everytime i increment my version numbers in module.inc?

 
mindless
mindless's picture

Joined: 2004-01-04
Posts: 8601
Posted: Mon, 2006-04-03 05:07

no, the makefile stuff is still there, though it now generates fewer files.
and yes, schema upgrades are not automatic anymore.. you do need to call configureStore as you show above.. that's for schema changes/upgrades only (xml_src/A_*.xml).. new tables are still created without any module.inc code.

 
nospamisgoodspam

Joined: 2005-08-31
Posts: 40
Posted: Mon, 2006-04-03 06:35

is there somewhere I can get the makefiles needed to create my module, I had some from version 2.0 when i first built my module but they seem to be corrupt now(they access stuff that doesn't exist and fail).

 
mindless
mindless's picture

Joined: 2004-01-04
Posts: 8601
Posted: Mon, 2006-04-03 14:48

just copy them from another 2.1 module.. just need GNUmakefile in the classes dir and classes/GalleryStorage dir now. you can remove the classes/interfaces and GalleryStorage/schema subdirs from 2.0.
if you have any maps, you need to remove the *.class files for them and make a Maps.xml.
http://codex.gallery2.org/index.php/Gallery2:API_Changes_From_2.0_To_2.1#2.4_.3D.3E_3.0

 
nospamisgoodspam

Joined: 2005-08-31
Posts: 40
Posted: Tue, 2006-04-04 04:17

Damn, looks like I need to do quite a bit to make my module compatible with the latest version of gallery, is it just me or do I need to replace all my get and set functions with direct access to the data members?


	//set
	$this->setOffset($offsetVal);
	//get
	offsetVal = $this->getOffset();

would be come


	//set
	$this->Offset = $offsetVal;
	//get
	offsetVal = $this->Offset;

-- or --


	//set
	$this['Offset'] = $offsetVal;
	//get
	offsetVal = $this['Offset'];

and maybe the save function (or something else) will update this in the database?

 
nospamisgoodspam

Joined: 2005-08-31
Posts: 40
Posted: Tue, 2006-04-04 08:32

So I tried something like that and none of my changes are saved into my item, is there some special call I should make like setDataMember or save?

 
mindless
mindless's picture

Joined: 2004-01-04
Posts: 8601
Posted: Tue, 2006-04-04 14:42

that's right, you need to add the get/set functions in the entity class. save() will save those changes, assuming a 'make' has been run to generate Entities.inc
if you still have trouble, perhaps post your code..

 
nospamisgoodspam

Joined: 2005-08-31
Posts: 40
Posted: Wed, 2006-04-05 00:26

so instead of being automatically generated I need to write my own get and set functions?

I replaced all my set usages

$this->setMember1($Member1);

with

$thisDataMember = (array)$this;
$thisDataMember['member1'] = $Member1;
$this->save();

I'm guessing this is wrong because it didn't work.

should I be calling

$thisDataMember->save()

instead?

Obviously I need a lock if I want to do this. Do I need to set a modified flag or something aswell?

I have run gmake on my classes and it did generate an Entities.php containing and array $entityInfo['MyItem'] with members, parent, module and linked. $entityInfo['MyItem2'] with similar values.

Should I be including this file at the end of my class files where I used to include the generated .inc files?

Would my previously generated inc files still work or has the fucntionality changed too much?

I don't really see in the Entities.inc file where I would put my functions to associate them with a member, should these get set functions go in my class file instead perhaps?

 
mindless
mindless's picture

Joined: 2004-01-04
Posts: 8601
Posted: Wed, 2006-04-05 15:45

yes, add the get/set functions in the entity .class file yourself. then do $entity->setFieldname('value'); and $entity->save(); just like in 2.0.x
no, you don't need to include Entities.inc yourself, nor should you edit it. the @g2 markers in your entity .class file are all you need.

 
talmdal

Joined: 2006-12-06
Posts: 358
Posted: Tue, 2006-12-12 16:25

Just a lttitle clarification please. If you are creating tables in a new module, do you create a Maps.xml and everthing get generated from it or Do you create the Entities.inc and that causes the everthing to be generated. Or do you have to create both. If you only is required, is there a preference to which approach is used? Or is it "situationaly dependent", in which case, what are recommendations on when to use which?

OrDo you create an Item class with the @g2 markup describing the members in the item and a helper class that provides the select criteria. Then run the GNUmakefile which generates the Entities.inc file.

Thanks
Tim

 
mindless
mindless's picture

Joined: 2004-01-04
Posts: 8601
Posted: Tue, 2006-12-12 19:53

You never make Maps.inc or Entities.inc, these are generated by the makefiles.

If you want to make a new entity type (has a php class, with get/set methods and a save() function) then define the class and use @g2 comments to define the db structure. Otherwise use Maps.xml to define a table that you can use for anything you like.. there are get/add/update/removeMapEntry functions in GalleryCoreApi. you can also use $gallery->search for more complex queries of your table (with joins, etc).

http://codex.gallery2.org/index.php/Gallery2:Module_Development_Tutorial#Working_With_the_Database

 
talmdal

Joined: 2006-12-06
Posts: 358
Posted: Tue, 2006-12-12 20:38

Thanks for your response, I think it is starting to become alot clearer and make some sense as well. Is there any guidelines as to when you would use an entity type vs. a map type? Or is it just personal preference.

 
mindless
mindless's picture

Joined: 2004-01-04
Posts: 8601
Posted: Wed, 2006-12-13 05:50

sometimes you must use an entity, for example to make a new type of item stored in the gallery.. this will need to extend GalleryItem. other times both might work.. comments module uses an entity as a child of items (conveniently they are deleted when the item is deleted), but a map probably could have worked too.

 
insomnix

Joined: 2009-04-19
Posts: 24
Posted: Tue, 2009-08-18 05:35

I feel like I'm programing in circles. Could someone tell me where I am going wrong. I am creating the database table fine and all my fields are there. I just seem to be going in circles trying to read and write to the table. This module is a work in progress, so my drop downs have nothing in them yet. I have the get and set functions created, but when I call

Quote:
$form['location']= $item->getLocation();

I get an error

Quote:
Fatal error: Call to undefined method GalleryAlbumItem::getLocation() in /var/www/gallery/modules/locationfields/LocationFieldsItemEdit.inc on line 79

Any help would be greatly appreciated. I have attached my work in progress.

 
insomnix

Joined: 2009-04-19
Posts: 24
Posted: Thu, 2009-08-27 20:21

I am making a little headway, trying to wrap my head around how Gallery works. I'm not sure if there is something I need to register or if I have to have a helper class between my get and set statements and the .inc file. How do I use the get and set functions with this, I guess is the question.