Work towards recipe model

This commit is contained in:
Chris 2016-09-18 10:25:15 +01:00
parent 63a856dec2
commit a3fe0cbde1

View File

@ -39,7 +39,8 @@
# | viewed | int(10) unsigned | NO | | NULL | |
# +------------+--------------------------------+------+-----+---------+----------------+
# NOTE: ADD FIELDS: parent (int 10), metadata_id (int 10), remove update*,
# NOTE: ADD FIELDS: prev_id (int 10), metadata_id (int 10), remove update*,
# NOTE: Change source and notes fields to allow NULL
# NOTE: Use status field for marking as edited?
# +-----------+------------------+------+-----+---------+----------------+
@ -92,18 +93,51 @@ sub new {
# Recipe creation and deletion
## @method $ create(%args)
# Create a new recipe in the system, or edit a recipe setting the status of
# the old version to 'edited'. The args hash can contain the following, all
# fields are required unless indicated otherwise:
#
# - `previd`: (optional) ID of the recipe this is an edit of. If specified, the
# old recipe has its state set to 'edited', and the metadata context
# of the new recipe is created as a child of the old recipe to ensure
# editing works as expected.
# - `name`: The name of the recipe
# - `source`: (optional) Where did the recipe come from originally?
# - `timereq`: A string describing the time required for the recipe
# - `timemins`: How long does the recipe take in minutes, in total?
# - `yield`: A string describing how much stuff the recipe creates
# - `temp`: (optional) Oven preheat temperature
# - `temptype`: The type of units used for `temp`: 'C', 'F', 'Gas mark', or 'N/A'
# - `method`: HTML text containing the recipe instructions
# - `notes`: (optional) Additional information about the recipe
# - `typeid`: The recipe type ID
# - `statusid`: The recipe status ID
# - `creatorid`: The ID of the user who created the recipe
#
# @param args A hash, or reference to a hash, of values to use when creating
# the new recipe.
# @return A reference to a hash containing the new recipe ID on success,
# undef on error.
sub create {
my $self = shift;
my $args = hash_or_hashref(@_);
$self -> clear_error();
# We need a metadata context for the recipe
my $metadataid = $self -> _create_recipe_metadata($args -> {"previd"});
my $newh = $self -> {"dbh"} -> prepare("INSERT INTO `".$self -> {"settings"} -> {"database"} -> {"recipes"}."`
(`metadata_id`, `prev_id`, `name`, `source`, `timereq`, `timemins`, `yield`, `temp`, `temptype`, `method`, `notes`, `type_id`, `status_id`, `creator_id`, `created`)
VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, UNIX_TIMESTAMP())");
}
# ==============================================================================
# Private methods
## @method private $ _add_recipe_ingredients($recipeid, $ingredients)
# Add the specified ingredients to the recipe list for the specified recipe. This goes through
@ -132,7 +166,7 @@ sub _add_recipe_ingredients {
# Otherwise, it's a real ingredient, so we need to do the more complex work
} else {
# obtain the ingredient id
my $ingid = $self -> {"ingredient"} -> get_ingred_id($ingred -> {"name"})
my $ingid = $self -> {"ingredients"} -> get_id($ingred -> {"name"})
or return $self -> self_error("Unable to get ingreditent ID for '".$ingred -> {"name"}."': ".$self -> {"ingredient"} -> errstr());
# If we have an ID we can add the ingredient.
@ -140,7 +174,7 @@ sub _add_recipe_ingredients {
or return $self -> self_error("Unable to add ingredient '".$ingred -> {"name"}."' to recipe '$recipeid': ".$self -> {"dbh"} -> errstr());
# And increase the ingredient refcount
$self -> {"ingredient"} -> increase_refcount_byid($ingid);
$self -> {"system"} -> {"ingredients"} -> increase_refcount($ingid);
}
}
@ -149,43 +183,107 @@ sub _add_recipe_ingredients {
}
## @method $ add_recipe_tags($recipeid, $tags, $userid)
## @method $ add_recipe_tags($recipeid, $tags)
# Add the specified tags to a recipe, setting the provided userid as the creator for new tags.
#
# @param recipeid The id of the recipe to add the tags to.
# @param tags A string containing a comma-delimited list of tags.
# @param userid The id of the user creating the recipe.
# @param tags A string containing a comma-delimited list of tags, or a reference to an
# array of tag names.
# @return true on success, undef on error
sub add_recipe_tags {
my $self = shift;
my $recipeid = shift;
my $tags = shift;
my $userid = shift;
# Bomb immediately if the tags list is empty
return undef if(!$tags || length($tags) == 0);
# exit immediately if the tags list is empty; this is not an error, as the
# recipe /can/ be untagged.
return 1 if(!$tags);
# If tags isn't a reference, assume it's a scalar string
if(!ref($tags)) {
return 1 unless(length($tags));
# Split the tag after removing any extraneous whitespace between tags
$tags =~ s/\s*,\s*/,/g;
my @values = split(/,/, $tags);
$tags = \@values;
# If $tags is a reference, it has to be an array!
} elsif(ref($tags) ne "ARRAY") {
return $self -> self_error("Unsupported reference passed to add_recipe_tags(). Giving up.");
}
# Now we prepare the tag insert query for action
my $addh = $self -> {"dbh"} -> prepare("INSERT INTO ".$self -> {"settings"} -> {"database"} -> {"recipetags"}."
(`recipe_id`, `tag_id`)
VALUES(?, ?)");
# Go through each tag, adding it
foreach my $tag (@values) {
foreach my $tag (@{$tags}) {
# Try to get the tag id
my $tagid = $self -> {"ingredient"} -> get_tag_id($tag, $userid)
my $tagid = $self -> {"system"} -> {"tags"} -> get_id($tag)
or return $self -> self_error("Unable to obtain ID for tag '$tag'");
$addh -> execute($recipeid, $tagid)
or return $self -> self_error("Tag association failed: ".$self -> {"dbh"} -> errstr);
$self -> {"system"} -> {"tags"} -> increase_refcount($tagid)
or return $self -> self_error("Tag refcount change failed");
}
return 1;
}
# ==============================================================================
# Metadata related
## @method $ get_recipe_metadata($recipeid)
# Given a recipe ID, fetch the ID of the metadata context associated with the
# recipe.
#
# @param recipeid The ID of the recipe to fetch the context ID for
# @return A metadata context ID on success, undef on error.
sub get_recipe_metadata {
my $self = shift;
my $recipeid = shift;
$self -> clear_error();
my $metah = $self -> {"dbh"} -> prepare("SELECT `metadata_id`
FROM `".$self -> {"settings"} -> {"database"} -> {"recipes"}."`
WHERE `id` = ?");
$metah -> execute($recipeid)
or return $self -> self_error("Unable to execute recipe metadata lookup query: ".$self -> {"dbh"} -> errstr);
my $meta = $metah -> fetchrow_arrayref()
or return $self -> self_error("Request for non-existent recipe '$recipeid', giving up");
return $meta -> [0];
}
## @method private $ _create_recipe_metadata($previd)
# Create a metadata context for a new recipe. This will create the new context
# as a child of the metadata context for the specific previous recipe, if one
# is provided, to allow cascading permissions.
#
# @param previd Optional ID of the previous recipe. This should be set when
# editing a recipe; for new recipes, leave this as undef or 0.
# @return The ID of a new metadata context to attach the recipe to on success,
# undef on error.
sub _create_recipe_metadata {
my $self = shift;
my $previd = shift;
if($previd) {
my $parentid = $self -> get_recipe_metadata($previd)
or return undef;
return $self -> {"metadata"} -> create($parentid);
}
return $self -> {"metadata"} -> create($self -> {"settings"} -> {"config"} -> {"Recipe:base_metadata"} // 1);
}
1;