Krang::Story - the Krang story class
# create a new story
$story = pkg('Story')->new(title => "Foo",
slug => 'foo',
class => 'article',
categories => [10, 20]);
# basic setable fields
$story->title("Life is very long");
$story->slug("life");
$story->cover_date(Time::Piece->strptime("1/1/2004 12:00", "%D %R"));
# get the root element for this story my $element = $story->element();
# add contributors $story->contribs(@contribs);
# find some stories about Sam
my @stories = pkg('Story')->find(title_like => '%sam%');
# load a single story by id
my ($story) = pkg('Story')->find(story_id => 1);
# load a group of stories by id
my ($story) = pkg('Story')->find(story_ids => [1, 20, 30, 100]);
# save a story, incrementing version $story->save();
# check it in, now other people can check it out $story->checkin();
# checkout the story, no one else can edit it now $story->checkout();
# revert to version 1 $story->revert(1);
# get list of stories linked to from this story my @linked_stories = $story->linked_stories;
# get list of media linked to from this story my @linked_media = $story->linked_media;
This class provides methods to operate on story objects. A story
contains some story-specific data (title, cover date, etc.) and an
element tree rooted in element, an object of the Krang::Element
class.
Stories may be associated with contributors (objects of Krang::Contrib) and assigned scheduled actions (publish and expire).
Stories are checked-in, checked-out and versioned like media (Krang::Media) and templates (Krang::Template). However, unlike media and templates, they may also be moved to desks (Krang::Desk).
Stories may be assigned to multiple categories. However, one category is the primary category and determines the primary URL.
Story objects are composed of the following attributes. Unless
otherwise noted all attributes are accessible via standard
accessor/mutators. For example, the title attribute can be set
with:
$story->title("New title here");
And accessed with:
$title = $story->title();
If an attribute is marked (readonly) then its value cannot be set.
For example, you may not set checked_out directly; instead, call
the checkout() method.
story_id (readonly)story_uuid (readonly)titleslugnotescover_datepublish_datedesk_idmove_to_desk() below.
version (readonly)published_version (readonly)Returns 0 if the story has never been published.
preview_version (readonly)Returns 0 if the story has never been previewed.
category (readonly)undef until at least one
category is assigned. This is just a convenience method that returns
the first category in categories.
url (readonly)undef until at least one category
is assigned.
preview_url (readonly)undef until at least one
category is assigned.
categoriesThis attribute may be assigned with category_ids or Krang::Category objects. Only objects will be returned.
This attribute may be set with a list or an array-ref. For example:
# same result $story->categories(1024, 1028); $story->categories([1024, 1028]);
But a list of objects is always returned:
@categories = $story->categories;
This method may throw a Krang::Story::DuplicateURL exception if you
add a new category and it generates a duplicate URL. When this
exception is thrown the category list is still changed and you may
continue to operate on the story. However, if you try to call save()
you will receive the same exception.
urls (readonly)preview_urls (readonly)contribscontribs() method for interface details.
element (readonly)class (readonly)new()
this method returns the class object for the root element, a
descendent of Krang::ElementClass. Another way to access the same
object is object is through $story->element->class, but calling
$story->class avoids loading the element tree for the story if
it hasn't already been loaded.
checked_out (readonly)checked_out_by (readonly)hidden (readonly)find(). This is
determined by the story class, and set in
Krang::ElementClass::TopLevel.
$story = Krang::Story->new(class => 'Article', categories => [$cat, 1024, 1034], slug => "foo", title => "Foo")class, categories, slug and title are all
required. After this call the object is guaranteed to be in a valid
state and may be saved immediately with save().
Will throw a Krang::Story::DuplicateURL exception with a story_id or category_id field if saving this story would conflict with an existing story or category.
selected_contrib_type set according to their use with this story
object.
May be set two ways. First, a contributor may specified as a two-key hash containing the contrib_id and the contrib_type_id for the contributor. A single contributor can be present in the list multiple times with different contrib_type_ids.
Second, a list of contributor objects with selected_contrib_type() set
may be passed in.
clear_contribs()$all_version_numbers = $story->all_versions();$story->prune_versions(number_to_keep => 10);prune_versions() keeps
the number of versions specified by SavedVersionsPerStory in krang.conf;
this can be overridden as above. In either case, it returns the number of
versions actually deleted.
$story->save()$story->save(keep_version => 1, no_history => 1, no_verify_checkout => 1)keep_version is true. Add appropriate entries to the history
and story_version tables unless no_history is true.
If the story is not checked out by the user attempting the save, then
an error will be thrown unless no_verify_checkout is true.
Will throw a Krang::Story::DuplicateURL exception with a story_id field
if saving this story would conflict with an existing story or category.
Will throw a Krang::Story::MissingCategory exception if this story
doesn't have at least one category. This can happen when a clone()
results in a story with no categories.
Will throw a Krang::Story::NoCategoryEditAccess exception if the
current user doesn't have edit access to the primary category set for
the story.
Will throw a Krang::Story::NoEditAccess exception if the current user
doesn't have edit access to the story.
@stories = Krang::Story->find(title => "Turtle Soup")@story_ids = Krang::Story->find(title => "Turtle Soup", ids_only => 1)$count = Krang::Story->find(title => "Turtle Soup", count => 1)Fields may be matched using SQL matching. Appending ``_like'' to a field name will specify a case-insensitive SQL match. For example, to match a sub-string inside title:
@stories = pkg('Story')->find(title_like => '%' . $search . '%');
Notice that it is necessary to surround terms with '%' to perform sub-string matches.
Available search options are:
undef returns all stories.
undef, specifying no limit in that direction.
undef, specifying no limit in that direction.
story_id (and only story_id), loads a specific
version of a story. Unlike revert(), this object has version
set to the actual version number of the loaded object.
@stories = pkg('Story')->find(element_index_like => [deck => '%foo%']);
Options affecting the search and the results returned:
find() should not return live stories. The
default is 1.
NOTE:When searching for story_id, these three include_* flags are not taken into account!
Krang::Story->hidden()
is false.
If you are developing an element set, you may or may not want this
option - See Krang::ElementClass::TopLevel for more information on
hidden().
NOTE: show_hidden is automatically enabled if any of the
following search terms are used: story_id, checked_out,
checked_out_by, class, desk_id, may_see, may_edit.
WARNING - A NOTE TO KRANG DEVELOPERS: Be aware that unless the
above search terms are used, you MUST use this modifier whenever UI
or bin/ scripts make calls to find()!
Krang::Story->transform_stories(%args)It takes the following named arguments:
This subroutine is expected to return the transformed version of the story.
Any other arguments passed in will be sent to the find() method.
# add a foo element to all stories of the "bar" class
pkg('Story')->transform_stories(
class => ['bar'],
past_versions => 1,
callback => sub {
my %args = @_;
my ( $story, $live ) = @args{ qw( story live ) };
my $element = $story->element;
$element->add_child(class => 'foo', value => 'blah, blah');
return $story;
},
);
$story->move_to_desk($desk_id)If the story is checked out and thus can't be moved to the desired
desk, throws a Krang::Story::CheckedOut exception.
If the desk has been deleted in the meantime, throws a
Krang::Story::NoDesk exception.
$story->checkout()Krang::Story->checkout($story_id)Krang::Story->checkin($story_id)$story->checkin()$story->mark_as_published()publish_date and
published_version attributes, and will also check the story back
in, removing it from any desk it's currently on.
This will also make an entry in the log that the story has been published.
$story->mark_as_previewed(unsaved => 1)preview_version
attribute, setting it equal to version. This is used as a sanity
check by Krang::Publisher to prevent re-generation of content.
The argument unsaved defaults to 0. If true, it indicates that the
story being previewed is in the process of being edited, in which case
any previews made cannot be trusted for future use. In that case,
preview_version is set to -1.
If a category is not passed the primary category for the story is returned.
Takes an optional category argument, or will return a url based on the story's primary category.
$story->revert($version)If you want to load an old version directly, see find().
$story->delete()Krang::Story->delete($story_id)$copy = $story->clone()$copy = $story->clone(category_id => $category_id)story_id and element->element_id which will both be
undef. Also, the copy gets a new story_uuid. It will be checked
out by the current user and it will not be saved.
If no category ID is passed in, a raw clone is assumed: In this case,
the title will be set to ``Copy of $title'' and
$clone->resolve_url_conflict() will be called to provide the clone
with non-conflicting URL(s) derived from the URL(s) of the original.
If a category ID is specified, no further DuplicateURL checks will be performed, and the clone will live in this category.
$story->resolve_url_conflict(append => 'copy')If the story has a slug, the string specified in append will be
appended to the story's slug.
Otherwise, the story's category_ids, category_cache and url_cache lists will be cleared.
@linked_stories = $story->linked_stories@linked_media = $story->linked_media$data = Storable::freeze($story)STORABLE_freeze() to
ensure this works correctly.
$story = Storable::thaw($data)STORABLE_thaw()
to ensure this works correctly.
$story->serialize_xml(writer => $writer, [set => $set, no_elements => 1])$story = Krang::Story->deserialize_xml(xml => $xml, set => $set, no_update => 0)If an incoming story has the same primary URL as an existing story then an update will occur, unless no_update is set.
$story->retire()Krang::Story->retire(story_id => $story_id)$story->unretire()Krang::Story->unretire(story_id => $story_id)$story->trash()Krang::Story->trash(story_id => $story_id)$story->untrash()Krang::Story->untrash(story_id => $story_id)$story->wont_publish()$story->turn_into_category_index(category => $category)$story->turn_into_category_index(category => $category, steal => 1)Turns the slug-provided $story into a slugless index page of the specified $category.
Returns undef if user can't check out the story.
When specifiying the flag steal, stories checked out by another user will be stolen if we have the necessary user admin permission 'may_checkin_all'. Otherwise returns undef.