NAME
OP::ExtID - Overloaded object class for foreign key constraints.
Extends OP::Str.
SYNOPSIS
use OP qw| :all |;
create "YourApp::Example" => {
categoryId => OP::ExtID->assert(
"YourApp::Category"
),
};
PUBLIC CLASS METHODS
$class->assert([$query], @rules)
ExtID assertions are like pointers defining relationships with other classes, or within a class to define parent/child hierarchy.
Attributes asserted as ExtID must match an id in the specified class's database table.
ExtID may be wrapped in an Array assertion for handling one-to-many relationships, at a small performance cost.
If using MySQL,
ExtID
also enforces database-level foreign key constraints. In addition to enforcing allowed values on the database level, this will incur a CASCADE operation on DELETE and UPDATE events (meaning if a parent is deleted or updated, the corresponding child rows will be deleted or updated as well; always use parent id in a child object, rather than child id in a parent object).The following example illustrates self-referencing and externally referencing attributes with ExtID, using the "Folder" and "Document" desktop paradigm. Each saved object becomes a row in a database table.
Create a folder class for documents and other folders:
# # File: ExampleFolder.pm # use OP qw| :all |; create "OP::ExampleFolder" => { # # Folders can go in other folders: # parentId => OP::ExtID->assert( "OP::ExampleFolder", subtype( optional => 1 ) ), ... };
A document class. Documents refer to their parent folder:
# # File: ExampleTextDocument.pm # use OP qw| :all |; use OP::ExampleFolder; create "OP::ExampleTextDocument" => { # # This doc's location in the folder hierarchy # folderId => OP::ExtID->assert("OP::ExampleFolder"), # # Textual content of the document # content => OP::Str->assert( subtype( columnType => "TEXT" ) ), # ... };
Caller example which populates some test folders and docs:
#!/bin/env perl # # File: somecaller.pl # use strict; use warnings; use OP::ExampleFolder; use OP::ExampleTextDocument; sub main { # # A parent folder named "General" # my $folder = OP::ExampleFolder->spawn("General"); $folder->save(); # # A child folder named "Specific" # my $subfolder = OP::ExampleFolder->spawn("Specific"); $subfolder->setFolderId( $folder->id() ); $subfolder->save(); # # Put a test document "README" in the parent folder: # my $readme = OP::ExampleTextDocument->spawn("README"); $readme->setFolderId( $folder->id() ); $readme->setContent("Lorem Ipsum Foo! Bla bla bla..."); $readme->save(); # # Put a "Test Text Doc" doc in the sub-folder: # my $doc = OP::ExampleTextDocument->spawn("Test Text Doc"); $doc->setFolderId( $subfolder->id() ); $doc->setContent("Lorem Ipsum Foo! Bla bla bla..."); $doc->save(); } main();
If a string is specified as a second argument to ExtID, it will be used as a SQL query, which selects a subset of Ids used as allowed values at runtime. If this query is not given, a flat, immutable list of Ids will be plugged in for allowed values at compile time.
create "OP::Example" => { userId => OP::ExtID->assert( "OP::Example::User", "select id from example_user where foo = 1" ), # ... };
SEE ALSO
This file is part of OP.