Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

No docs about many-to-many relationships #45

Closed
teo1978 opened this issue Sep 1, 2019 · 2 comments
Closed

No docs about many-to-many relationships #45

teo1978 opened this issue Sep 1, 2019 · 2 comments

Comments

@teo1978
Copy link

teo1978 commented Sep 1, 2019

I read the documentation, and then started writing a plugin by looking at the source code from an existing plugin, and inspecting the source code of Omeka, because reading the documentation left me exactly at the same point where I was before reading it.

I needed to create a table representing a Many-to-Many relationship between two models. That means that the primary key is made of two fields, one referencing the id of a table represeting one model, and the other referencing the id of the table representing another model. In a standard mapping of an Entity-Relation model to a database structure, the table representing the many-to-many relation shouldn't have a useless, redundant, auto-increment 'id' field, it just has the primary key built with the ids referencing the two model tables.

There's NOTHING about this in the documentation, so I tried.

This is the statement creating the table in the installation hook:

CREATE TABLE IF NOT EXISTS `{$this->_db->AdditionalParentCollection}` (
          `parent_collection_id` int(10) unsigned NOT NULL,
          `collection_id` int(10) unsigned NOT NULL,
          PRIMARY KEY (`parent_collection_id`, `collection_id`)
        ) ENGINE=InnoDB  DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;";
        $this->_db->query($sql);

This is a many-to-many relationship between Collection and Collection. What it means and what it's for are not relevant here.

I created a model AdditionalParentCollection and a table Table_AdditionalParentCollection.

I find NOTHING in the documenation about how I'm supposed to tell Omeka that this table represents a relation and not a model, and/or that the primary key is not id, let alone that it's made of two fields. So I thought I'd try by just never using find() (only findBy()) and never mentioning the id and see what would happen.

In my hookAfterSaveCollection I have this:

				$additionalParent = new AdditionalParentCollection;
				$additionalParent->collection_id = $collection->id;
				$additionalParent->parent_collection_id = $additionalParentId;
				$additionalParent->save();

This looks like it shouldn't cause any problem by itself. I'm creating a new instance of the model, populating the only two fields that it has, and trying to save it.

This causes this error:

exception 'Zend_Db_Statement_Mysqli_Exception' with message 'Mysqli prepare error: Unknown column 'id' in 'field list'' in /srv/www/****/application/libraries/Zend/Db/Statement/Mysqli.php:77
Stack trace:
#0 /srv/www/****/application/libraries/Zend/Db/Statement.php(115): Zend_Db_Statement_Mysqli->_prepare('INSERT INTO `ad...')
#1 /srv/www/****/application/libraries/Zend/Db/Adapter/Mysqli.php(388): Zend_Db_Statement->__construct(Object(Zend_Db_Adapter_Mysqli), 'INSERT INTO `ad...')
#2 /srv/www/****/application/libraries/Zend/Db/Adapter/Abstract.php(479): Zend_Db_Adapter_Mysqli->prepare('INSERT INTO `ad...')
#3 [internal function]: Zend_Db_Adapter_Abstract->query('INSERT INTO `ad...', Array)
#4 /srv/www/****/application/libraries/Omeka/Db.php(79): call_user_func_array(Array, Array)
#5 /srv/www/****/application/libraries/Omeka/Db.php(255): Omeka_Db->__call('query', Array)
#6 /srv/www/****/application/libraries/Omeka/Db.php(255): Omeka_Db->query('INSERT INTO `ad...', Array)
#7 /srv/www/****/application/libraries/Omeka/Record/AbstractRecord.php(541): Omeka_Db->insert('AdditionalParen...', Array)
#8 /srv/www/****/plugins/AdditionalParents/AdditionalParentsPlugin.php(172): Omeka_Record_AbstractRecord->save()
#9 [internal function]: AdditionalParentsPlugin->hookAfterSaveCollection(Array)
#10 /srv/www/****/application/libraries/Omeka/Plugin/Broker.php(154): call_user_func(Array, Array)
#11 /srv/www/****/application/libraries/Omeka/Record/AbstractRecord.php(301): Omeka_Plugin_Broker->callHook('after_save_coll...', Array)
#12 /srv/www/****/application/libraries/Omeka/Record/AbstractRecord.php(548): Omeka_Record_AbstractRecord->runCallbacks('afterSave', Array)
#13 /srv/www/****/application/libraries/Omeka/Controller/AbstractActionController.php(229): Omeka_Record_AbstractRecord->save(false)
#14 /srv/www/****/application/controllers/CollectionsController.php(52): Omeka_Controller_AbstractActionController->editAction()
#15 /srv/www/****/application/libraries/Zend/Controller/Action.php(516): CollectionsController->editAction()
#16 /srv/www/****/application/libraries/Zend/Controller/Dispatcher/Standard.php(308): Zend_Controller_Action->dispatch('editAction')
#17 /srv/www/****/application/libraries/Zend/Controller/Front.php(954): Zend_Controller_Dispatcher_Standard->dispatch(Object(Zend_Controller_Request_Http), Object(Zend_Controller_Response_Http))
#18 /srv/www/****/application/libraries/Zend/Application/Bootstrap/Bootstrap.php(105): Zend_Controller_Front->dispatch()
#19 /srv/www/****/application/libraries/Zend/Application.php(384): Zend_Application_Bootstrap_Bootstrap->run()
#20 /srv/www/****/application/libraries/Omeka/Application.php(73): Zend_Application->run()
#21 /srv/www/****/admin/index.php(28): Omeka_Application->run()
#22 {main}

which, as per another annoying bug I reported a few minutes ago, doesn't even show me the full query that causes the error.

I wouldn't necessarily expect this to work as is. I would expect to be able to find, in the documentation, an explanation of how I am supposed to do this.
And I believe I know how to look. I don't think I'm not finding it in the documentation because I don't know where to look or because it's obvious enough. I'm not finding it because it's not there.
Nor is there a link to a place where to look (e.g., if Omeka is built on top of some other well-known framework, a link to its documentation or a mention of its name)

@zerocrates
Copy link
Member

The Omeka "classic" ORM is home-grown; the only framework it's built on is Zend_Db which is a very lightweight abstraction layer. All the "ORM" functionality is Omeka-specific.

You are correct, you're not finding this in the documentation because it isn't there. More than not being documented, the feature simply doesn't exist. Omeka and its plugins turn out to use very few many-to-many relationships, so the Omeka_Record system doesn't have any facilities for dealing with database tables without an ID column. If you want to use the ORM for a table like this, you have to just accept the unnecessary IDs. Otherwise you can manage the rows "manually" and only have them interface with the ORM by being used in joins. The "default" Omeka Classic way to handle this situation would just be to accept the IDs.

For many reasons including this one, Omeka S uses Doctrine as its ORM, which allows for fine-grained control over primary keys and also automatic handling of many-to-many relationships. A major focus of "classic" Omeka is backwards compatibility and so major changes to core components like these are unlikely.

@teo1978
Copy link
Author

teo1978 commented Sep 3, 2019

If you want to use the ORM for a table like this, you have to just accept the unnecessary IDs. Otherwise you can manage the rows "manually" and only have them interface with the ORM by being used in joins. The "default" Omeka Classic way to handle this situation would just be to accept the IDs.

This is the kind of information I would expect to find in the docs. It would have saved me time.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants