WTF::Utils - Container for data and framework utility functions


VERSION

This document describes WTF::Utils version 1.02


SYNOPSIS

        use WTF::Utils;
        my $work = WTF::Utils::tree_data(
                $sth->{'myweekly'}->fetchall_arrayref({}),
                'work_day', 'days',
        );
        my $req = WTF::Utils::get_req($r);
        $tmpl_obj->param(
                'title'   => 'My Weekly Time',
                'nav_bar' => WTF::Utils::nav_bar_data( $r, 'myweekly' ),
        );
        my $workbook = WTF::Utils::make_excel_workbook( $r, $filename );
        my $formats  = WTF::Utils::make_excel_formats($workbook);
        my $team_id  = WTF::Utils::my_team_id($user_id);
        my $team_ids = WTF::Utils::generate_team_ids($user_id);
        my ( $date_start, $date_end ) = WTF::Utils::date_range( '2006-10-01', 7 );
        my $htmlized_notes = WTF::Utils::htmlize_notes(
                $sth->{'notes'}->fetchall_arrayref({})
        );
        my @indented_data = @{ WTF::Utils::indent(
                $sth->{'data'}->fetchall_arrayref({}),
                'parent_id',
                \&function,
        );


DESCRIPTION

This module is a container for data and framework utility functions. These functions are mostly stand-alone functions called from throughout the WTF framework.


FUNCTIONS

There are a bunch of random-ish functions this module contains.

tree_data()

This function mutates a ``flat-ish'' data structure into a data tree. The goal is to accept an incoming ``flat-ish'' data structure from a database query and return a tree structure based on certain columns being tree nodes. The data returned should be in a condition such that it's ready to be directly dropped into an HTML::Template template parameter.

This function requires an incoming data structure from a ``fetchall_arrayref({})'' call and some number of additional inputs describing the desired tree.

        my $work = WTF::Utils::tree_data(
                $sth->{'myweekly'}->fetchall_arrayref({}),
                'work_day', 'days',
        );

The first input item must be an array reference to anonymous hashes. In this example, the next input is the key name in the anonymous hash that should be used to build a tree node. The last input is the name of the group that will contain records that match the anonymous hash key name. For example, assume that the ``$sth->{'myweekly'}'' query returned a reference to an array containing data similar to this:

        {
                'work_day'    => 'Friday, October 6, 2006',
                'task_id'     => 1138,
                'employee_id' => 77,
        },
        {
                'work_day'    => 'Friday, October 6, 2006',
                'task_id'     => 42,
                'employee_id' => 77,
        },
        {
                'work_day'    => 'Thursday, October 5, 2006',
                'task_id'     => 1024,
                'employee_id' => 77,
        },

The above ``tree_data()'' example call would look for equal ``work_day'' values in the series and merge remaining data elements into a ``days'' anonymous array. The resulting output should be similar to this:

        {
                'work_day' => 'Friday, October 6, 2006',
                'days'     => [
                        {
                                'task_id'     => 1138,
                                'employee_id' => 77,
                        },
                        {
                                'task_id'     => 42,
                                'employee_id' => 77,
                        },
                ],
        },
        {
                'work_day'    => 'Thursday, October 5, 2006',
                'days'     => [
                        {
                                'task_id'     => 1024,
                                'employee_id' => 77,
                        },
                ],
        },

This process also works for multiple layers of nesting in a tree. For example, instead of ``qw( work_day days )'', you could have ``qw( work_day days employee_id tasks )'' and so forth. The requirement is that the number of these strings should always be even: the first in the pair is the key name, and the second is the grouping name.

It's also possible to switch-out a key name (the first element in a pair) with a reference to an array containing multiple strings. In this case, the first string in the inner sequence will be used for the key name and all the remaining strings will be considered keys from the original data that should be moved into the same tree segment. Consider the following call:

        my $data = WTF::Utils::tree_data(
                $sth->{'another_sql_query'}->fetchall_arrayref({}),
                'team', 'employees', [ 'employee', 'employee_id' ], 'work_days'
        );

Let's say that the original ``$sth->{'another_sql_query'}'' data looks something like this:

        {
                'team'        => 'Alliance',
                'employee'    => 'Luke',
                'employee_id' => 77,
                'work_day'    => '2006-10-01',
        },
        {
                'team'        => 'Alliance',
                'employee'    => 'Luke',
                'employee_id' => 77,
                'work_day'    => '2006-10-02',
        },
        {
                'team'        => 'Alliance',
                'employee'    => 'Han',
                'employee_id' => 52,
                'work_day'    => '2006-10-01',
        },
        {
                'team'        => 'Empire',
                'employee'    => 'Vader',
                'employee_id' => 12,
                'work_day'    => '2006-10-01',
        },

This call should result in ``$data'' containing a data structure similar to this:

        {
                'team'      => 'Alliance',
                'employees' => [
                        {
                                'employee'    => 'Luke',
                                'employee_id' => 77,
                                'work_days' => [
                                        'work_day' => '2006-10-01',
                                        'work_day' => '2006-10-02',
                                ],
                        },
                        {
                                'employee'    => 'Han',
                                'employee_id' => 52,
                                'work_days' => [
                                        'work_day' => '2006-10-01',
                                ],
                        },
                ],
                'team'      => 'Empire',
                'employees' => [
                        {
                                'employee'    => 'Vader',
                                'employee_id' => 12,
                                'work_days' => [
                                        'work_day' => '2006-10-01',
                                ],
                        },
        },

get_req()

This function returns an Apache2::Request object with some safe parameters like upload disabling and a reasonable maximum POST size. This function requires an Apache request (Apache2::RequestRec) object as input.

        my $req = WTF::Utils::get_req($r);
        my $form_element_data = $req->param('form_element_name');

nav_bar_data()

This function returns an array reference containing an anonymous hash with a series of parameters. This data is in a format suitable for direct placement in an HTML::Template object's ``param()'' call to populate the page navigation bar on most WTF pages.

        $tmpl_obj->param(
                'title'   => 'My Weekly Time',
                'nav_bar' => WTF::Utils::nav_bar_data( $r, 'myweekly' ),
        );
        return $tmpl_obj->output();

This function requires two inputs. The first input is an Apache request (Apache2::RequestRec) object. The second input is the string corresponding to the name of the current page. This second input will be used to toggle a ``current_*'' parameter flag that the navigation bar HTML::Template template will use to indicate in the navigation bar display what page the user is on.

This function will return data to set the following within a navigation bar:

make_excel_workbook()

This function requires an Apache request (Apache2::RequestRec) object and a local filename and returns a Spreadsheet::WriteExcel object. In the process, the function sets HTTP headers and ties output to the Spreadsheet::WriteExcel object, making it easier to build and return Microsoft Excel files.

        sub xls_make {
                my ($r)       = @_; # $r is the Apache2::RequestRec object
                my $filename  = 'excel_file.xls';
                my $workbook  = WTF::Utils::make_excel_workbook( $r, $filename );
                my $worksheet = $workbook->add_worksheet('Sheet Title');
                $workbook->close();
                return;
        }

In the above example, ``xls_make()'' creates an Excel file with a single worksheet in it titled ``Sheet Title''. It returns that file to the browser with the default filename ``excel_file.xls''.

make_excel_formats()

This function requires a Spreadsheet::WriteExcel object as input. It builds a series of common spreadsheet formats and returns them in a reference to a hash where the keys are the names of the formats.

        my $formats = WTF::Utils::make_excel_formats($workbook);
        $worksheet->write( 0, 0, 'Sheet Title', $formats->{'title'} );

my_team_id()

This function requires a user ID and returns the team ID for that user account.

        my $team_id = WTF::Utils::my_team_id($user_id);

generate_team_ids()

This function requires a user ID and returns the team ID and all sub-team IDs.

        my $team_ids = WTF::Utils::generate_team_ids($user_id);

This function is equivalent to ``my_team_id()'' if the particular user has no sub-teams or is not a manager.

date_range()

This function requires two parameters and can accept up to four. It returns a date range suitable for use in MySQL ``WHERE x BETWEEN y AND z'' queries where ``y'' and ``z'' are date strings.

        my ( $date_start, $date_end ) = WTF::Utils::date_range( $date, $days );

In the example above, ``$date'' is a MySQL date string and ``$days'' is an integer. The function will return two date strings in a range that begins on the Sunday just before ``$date'' and ends ``$days'' number of days later. If either the first or the second parameter is 0, then the function will assume the current date for either input.

        my @range1 = WTF::Utils::date_range( '2006-10-04', 7 );
        # @range1 = ( '2006-10-01', '2006-10-07' );
        my @range2 = WTF::Utils::date_range( 0, 3 );
        # @range1 -> most recent Sunday past, the Tuesday after that Sunday
        my @range2 = WTF::Utils::date_range( 0, 0 );
        # @range -> most recent Sunday past, current day

The third and four inputs, which are optional, allow for overriding the start and end dates.

        my ( $date_start, $date_end ) = WTF::Utils::date_range(
                0, 0,
                $req->param('date_start'),
                $req->param('date_end'),
        );

The above example operates similarly to to the last previous example except that if ``$req->param('date_start')'' is a valid date, then it will be used as the first parameter input instead of 0, and if ``$req->param('date_end')'' is a valid date, then it will be used as the second parameter input instead of 0.

htmlize_notes()

This function prepares note content for display on a web page. It expects a reference to an array of hash references where the hashes contain a ``notes'' key with some text as the value. The function is intended to be used directly on the returned data from a notes SQL call.

        my $htmlized_notes = WTF::Utils::htmlize_notes(
                $sth->{'notes'}->fetchall_arrayref({})
        );

The function adds HTML breaks before each newline. It also tries to ensure that multiple spaces don't get compressed by the browser. It'll also escape any HTML markup in the note content.

indent()

This function requires a reference to a data structure similar to what would be returned from a ``$sth->fetchall_arrayref({})'' call. It also requires a ``indent key'' (a column within each row that is typically a foreign key to the primary key of the same table).

        my @indented_data = @{ WTF::Utils::indent(
                $sth->{'data'}->fetchall_arrayref({}),
                'parent_id',
        );

The function returns a reference to an array that is structurally similar to the ``$sth->fetchall_arrayref({})'' input, but each row will contain an additional key called ``indent'' that will contain an integer starting at 0 indicating how many indent levels at which the particular row should be displayed. Each row may also contain a ``group'' key containing a boolean that indicates whether the row is a group, meaning that it has items ``below'' it that are children.

The function will optionally take a third argument, which is a reference to a function that will run against each row on that row's data after the indent level is assigned. The anonymous function will get passed a reference to the row of data (a reference to a hash).

        my @indented_data = @{ WTF::Utils::indent(
                $sth->{'data'}->fetchall_arrayref({}),
                'parent_id',
                sub {
                        my ($row) = @_;
                        $row->{'indent_plus_five'} = $row->{'indent'} + 5;
                },
        );


DEPENDENCIES

WTF::Utils depends on the following modules:


KNOWN ISSUES

The ``tree_data()'' function mutates the incoming data structure as it's creating the new structure to return. This isn't a problem presently, but it may be a problem later. Regardless, it's probably a good idea to rewrite this function to not mutate the incoming data structure.

Some of the functions are not written very efficiently. There can be performance gains realized if there's a refactoring of a few of the functions.


COPYRIGHT, LICENSE, AND DISCLAIMER OF WARRANTY

Use of this module implies the reading and agreement with the license under which this software is release. That license can be found in the ``license.txt'' file included with this distribution.