Krang::Category - a means to access information on categories
use Krang::ClassLoader 'Category';
# construct object
my $category = Krang::Category->new(dir => 'category', # required
parent_id => 1,
site_id => 1);
# 'parent_id' must be present for all categories except '/' 'site_id' # must be present for '/'
# saves object to the DB $category->save();
# getters my $element = $category->element(); my $dir = $category->dir(); my $id = $category->parent_id(); my $parent = $category->parent(); my $id = $category->site_id(); my $site = $category->site(); my $may_see = $category->may_see(); my $may_edit = $category->may_edit();
my $id = $category->category_id(); # undef until after save() my $id = $category->element_id(); # undef until after save() my $url = $category->url(); # undef until after save()
# setters $category->dir( $some_single_level_dirname );
# delete the category from the database $category->delete();
# a hash of search parameters
my %params =
( order_desc => 1, # result ascend unless this flag is set
limit => 5, # return 5 or less category objects
offset => 1, # start counting result from the
# second row
order_by => 'url' # sort on the 'url' field
dir_like => '%bob%', # match categories with dir LIKE '%bob%'
parent_id => 8,
site_id => 9,
url_like => '%fred%' );
# any valid object field can be appended with '_like' to perform a # case-insensitive sub-string match on that field in the database
# returns an array of category objects matching criteria in %params
my @categories = pkg('Category')->find( %params );
Categories serve three purposes in Krang. They serve as a means of dividing a
sites content into distinct areas. Consequently, all content sharing the
property of ``being chiefly about 'X''' should be placed within category 'X'. A
category's dir, such as '/X', translates to both a relative system filepath for
preview and publish output and a URL relative path. For example category '/X'
would map to $site->publish_path() . '/X' as well as 'http://' . $site->url() .
'/X'.
Secondly, categories serve as a data container. The 'element' field of a category object is a Krang::Element wherein arbitrary information about the category may be stored.
Thirdly, once a template object is associated with its element, a category serves to provide a layout container for story content that belongs to it. All of the fields defined in the category's element will be available to this template and may be used to derive category-specific layout behavior.
This module serves as a means of adding, deleting, and accessing these objects.
N.B. Categories must be associated with a site via the 'site_id' constructor arg or a 'parent_id' must be passed.
Access to fields for this object is provided my Krang::MethodMaker. The value of fields can be obtained and set in the following fashion:
$value = $category->field_name(); $category->field_name( $some_value );
The available fields for a category object are:
If the category being created is a subcategory (e.g. it has a parent_id), the value of dir should be the subdirectory itself, NOT the full directory path - that will be handled internally by Krang::Category.
N.b.: The new() method will throw and exception, Krang::Category::NoEditAccess,
if the current user does not have edit access to the parent category.
delete()This method's underlying call to dependent_check() may result in a
Krang::Category::Dependency exception if an object in the system is found that
relies upon the Category in question.
N.B. - If this call attempts to remove a root category (i.e. a category whose 'dir' field eq '/') and the call is not made by Krang::Site, a Krang::Category::RootDeletion exception will be thrown. This behavior exists because the deletion of a root category results in a disabled Site. The user would be unable to add categories to this given Site and to correct this he would have to know that he must add another root category before and subcategories could again be added to the Site. This behavior is preferable to requiring so comprehensive an understanding of the API by the user :).
This method will throw a Krang::Category::NoEditAccess exception if a user without edit access tries to delete the category.
dependent_check()Krang::Category::Dependent exceptions have one field 'dependents' that contains a hashref of the classnames and ids of the objects which depend upon the given category object. You might want to handle the exception thusly:
eval {$category->dependent_check()};
if ($@ and $@->isa('Krang::Category::Dependent')) {
my $dependents = $@->dependents();
$dependents = join("\n\t", map{"$_: [" .
join(",", @{$dependents->{$_}}) .
"]"} keys %$dependents);
croak("The following object classes and ids rely upon this " .
"category:\n\t$dependents);
} else {
die $@;
}
duplicate_check()Krang::Category::DuplicateURL exceptions have a single nonempty field - either 'category_id' or 'story_id' - that indicates the id of the clashing object
eval {$self->duplicate_check()};
if ($@ and $@->isa('Krang::Category::DuplicateURL')) {
if ($@->story_id) {
croak("The 'url' of this category duplicates that of story id: " .
$@->story_id\n");
} elsif {
croak("The 'url' of this category duplicates that of category id: " .
$@->category_id\n");
}
}
ancestors()root_category()descendants()children()Additional criteria which affect the search results are:
The method croaks if an invalid search criteria is provided or if both the 'count' and 'ids_only' options are specified.
element (readonly)save()update_child_url() is called to update the urls underneath
the present object.
The method croaks if the save would result in a duplicate category object (i.e. if the object has the 'dir' as another object). It also croaks if its database query affects no rows in the database.
This method will throw a Krang::Category::NoEditAccess exception if a user without edit access tries to save the category.
update_child_urls()@linked_stories = $category->linked_stories@linked_media = $category->linked_media$category->serialize_xml(writer => $writer, set => $set)$category = Krang::Category->deserialize_xml(xml => $xml, set => $set, no_update => 0, skip_update => 0)If an incoming category has the same URL as an existing category then an update will occur.
$data = Storable::freeze($category)STORABLE_freeze() to
ensure this works correctly.
$category = Storable::thaw($data)STORABLE_thaw()
to ensure this works correctly.
$category->can_copy_test(dst_category => $destination_category)can_copy_test() should always be called before
copy(), and it should be called with the same argument and the same
options to make sure the copy will succeed.
The following exceptions can occur:
Options
$category and its children
would succeed.
$category and its children
would succeed.
$category and its children
would succeed.
Krang::Category::CopyAssetConflict will be thrown even if the URL of
a would-be-created asset is already occupied by some other asset living
below the destination category.
$category->copy(dst_category => $destination_category)can_copy_test() with the same
argument and the same options before calling this method!
Options:
Concerning the following three options note that stories/media/templates whose would-be-URL is occupied by some existing asset will not be copied, but silently skipped. But see the option 'overwrite'.
Note on calling can_copy_test() and copy() with overwrite set to false
In the case of an asset conflict, can_copy_test() throws a
Krang::Category::CopyAssetConflict exception, while copy() simply
skips the conflicting assets. Catching the exception, then, allows to
prompt the user: Does he want to cancel the whole copy, or is it ok to
just copy the non-conflicting assets. This is how runmode
Krang::CGI::Category->execute_copy() uses these two methods.
@assets = $category->asset_names()@assets = pkg('Category')->asset_names()The 'type' key of each of these hashrefs is just the lower-cased moniker of those assets, i.e. 'story', 'media' and 'template'.
The 'meth' key maps to the asset's 'file name' method: It's 'slug' for Story, 'filename' for Media and Template.
Krang, Krang::DB, Krang::Element