<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Savant</title>
	<atom:link href="http://jordansavant.com/feed" rel="self" type="application/rss+xml" />
	<link>http://jordansavant.com</link>
	<description>Just another WordPress site</description>
	<lastBuildDate>Sat, 16 Jun 2012 12:55:57 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.2.1</generator>
		<item>
		<title>Programming in PHP: Axis Entity Object Helper</title>
		<link>http://jordansavant.com/programming-in-php-axis-entity-object-helper</link>
		<comments>http://jordansavant.com/programming-in-php-axis-entity-object-helper#comments</comments>
		<pubDate>Wed, 04 Jan 2012 05:15:04 +0000</pubDate>
		<dc:creator>Jordan Savant</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Projects]]></category>

		<guid isPermaLink="false">http://jordansavant.com/?p=376</guid>
		<description><![CDATA[Our Axis Entity Object class is quite powerful and useful for lightweight ORM. But lets go ahead and create a help class that will alleviate a lot of business and view coding by automating the create and update forms and &#8230; <a href="http://jordansavant.com/programming-in-php-axis-entity-object-helper">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Our <a href="http://jordansavant.com/programming-in-php-axis-entity-objects" title="Programming in PHP: Axis Entity Objects">Axis Entity Object</a> class is quite powerful and useful for lightweight ORM. But lets go ahead and create a help class that will alleviate a lot of business and view coding by automating the create and update forms and processing for Axis Entity Objects.</p>
<p>First lets look at how the code will operate in the business side of things. Here is how we generate the creation form for our example Axis Entity Object class &#8220;Fruit&#8221;:</p>
<pre class="brush: php; ">

&lt;form action=&quot;index.php&quot; method=&quot;post&quot;&gt;
    &lt;?php AxisObjectHelper::DrawFormCreate(&#039;Fruit&#039;); ?&gt;
    &lt;input type=&quot;submit&quot; /&gt;
&lt;/form&gt;
</pre>
<p>What you can see here is that our helper class will contain a static method for creating an update form for our class &#8220;Fruit&#8221;. Lets take a look at that code.</p>
<pre class="brush: php; ">

    public static function DrawFormCreate($class)
    {
        // get our fields from our mapped database table
        $fields = AxisObjectHelper::GetFields($class);

        // loop through the returned fields and generate input fields matching the name of the columns.
        foreach($fields as $field_object)
        {
            if($field_object-&gt;Key != &#039;PRI&#039;)
            {
                echo &#039;&lt;div class=&quot;object_field&quot; id=&quot;create_&#039;.$class.&#039;_field_&#039;.$field_object-&gt;Field.&#039;&quot;&gt;&#039;.self::PrettifyName($field_object-&gt;Field).&#039;&lt;/div&gt;&#039;;

                echo &#039;&lt;div class=&quot;object_input&quot; id=&quot;create_&#039;.$class.&#039;_input_&#039;.$field_object-&gt;Field.&#039;&quot;&gt;&#039;.self::DrawInput($field_object).&#039;&lt;/div&gt;&#039;;
            }
        }
    }
</pre>
<p>Generating the create form is simple as pie once we have the corresponding columns of the class.</p>
<p>Here is how we process the create form:</p>
<pre class="brush: php; ">

AxisObjectHelper::ProcessFormCreate(&#039;Fruit&#039;);
</pre>
<p>So simple! Again we have a single line of PHP for processing the user&#8217;s input and creating the object. Lets take a closer look at that static method.</p>
<pre class="brush: php; ">

    public static function ProcessFormCreate($class)
    {
        // get our table columns
        $fields = AxisObjectHelper::GetFields($class);

        // create a new instance of our Axis Entity Object
        $create = new $class();

        // loop through the fields and create them
        foreach($fields as $field_object)
        {
            if($field_object-&gt;Key != &#039;PRI&#039;)
            {
                $field_name = $field_object-&gt;Field;
                $create-&gt;$field_name = $_POST[$field_name];
            }
        }

        return $create-&gt;Create();
    }
</pre>
<p>Using the Axis Entity Object class, we leverage it&#8217;s ORM to create the object very simply.</p>
<p>Updating objects is just as simple requiring only two lines of PHP to generate the form and to process it. Here is the example helper class in its entirety.</p>
<pre class="brush: php; ">

class AxisObjectHelper
{
    public static function OpenMySQL($host, $db, $user, $pass)
    {
        mysql_connect($host, $user, $pass);
        mysql_select_db($db);
    }

    public static function DrawFormCreate($class)
    {
        // get our fields from our mapped database table
        $fields = AxisObjectHelper::GetFields($class);

        // loop through the returned fields and generate input fields matching the name of the columns.
        foreach($fields as $field_object)
        {
            if($field_object-&gt;Key != &#039;PRI&#039;)
            {
                echo &#039;&lt;div class=&quot;object_field&quot; id=&quot;create_&#039;.$class.&#039;_field_&#039;.$field_object-&gt;Field.&#039;&quot;&gt;&#039;.self::PrettifyName($field_object-&gt;Field).&#039;&lt;/div&gt;&#039;;

                echo &#039;&lt;div class=&quot;object_input&quot; id=&quot;create_&#039;.$class.&#039;_input_&#039;.$field_object-&gt;Field.&#039;&quot;&gt;&#039;.self::DrawInput($field_object).&#039;&lt;/div&gt;&#039;;
            }
        }
    }

    public static function ProcessFormCreate($class)
    {
        // get our table columns
        $fields = AxisObjectHelper::GetFields($class);

        // create a new instance of our Axis Entity Object
        $create = new $class();

        // loop through the fields and create them
        foreach($fields as $field_object)
        {
            if($field_object-&gt;Key != &#039;PRI&#039;)
            {
                $field_name = $field_object-&gt;Field;
                $create-&gt;$field_name = $_POST[$field_name];
            }
        }

        return $create-&gt;Create();
    }

    public static function DrawFormUpdate($object)
    {
        $class = get_class($object);
        $primary_key_column = strtolower($class).&#039;_id&#039;;

        $fields = AxisObjectHelper::GetFields($class);

        foreach($fields as $field_object)
        {
            if($field_object-&gt;Key != &#039;PRI&#039;)
            {
                $field_name = $field_object-&gt;Field;
                $object_field_value = $object-&gt;$field_name;

                echo &#039;&lt;div class=&quot;object_field&quot; id=&quot;update_&#039;.$class.&#039;_field_&#039;.$field_object-&gt;Field.&#039;_&#039;.$object-&gt;$primary_key_column.&#039;&quot;&gt;&#039;.self::PrettifyName($field_object-&gt;Field).&#039;&lt;/div&gt;&#039;;

                echo &#039;&lt;div class=&quot;object_input&quot; id=&quot;update_&#039;.$class.&#039;_input_&#039;.$field_object-&gt;Field.&#039;_&#039;.$object-&gt;$primary_key_column.&#039;&quot;&gt;&#039;.self::DrawInput($field_object, $object_field_value).&#039;&lt;/div&gt;&#039;;
            }
        }
    }

    public static function ProcessFormUpdate($class, $object_id)
    {
        $fields = AxisObjectHelper::GetFields($class);
        $update_object = call_user_func(array($class, &#039;Factory&#039;), $object_id, $class);

        foreach($fields as $field_object)
        {
            if($field_object-&gt;Key != &#039;PRI&#039;)
            {
                $field_name = $field_object-&gt;Field;
                $update_object-&gt;$field_name = $_POST[$field_name];
            }
        }

        return $update_object-&gt;Update();
    }

    public static function DrawInput($field_object, $value = &#039;&#039;)
    {
        // cases for input
        if(strpos($field_object-&gt;Type, &#039;tinyint&#039;) !== false &amp;&amp; strpos($field_object-&gt;Type, &#039;(1)&#039;) !== false)
        {
            if($value != &#039;&#039;)
            {
                if((bool)$value)
                {
                    return &#039;&lt;input type=&quot;checkbox&quot; class=&quot;input_boolean&quot; name=&quot;&#039;.$field_object-&gt;Field.&#039;&quot; value=&quot;1&quot; checked=&quot;checked&quot; /&gt;&#039;;
                }
            }

            return &#039;&lt;input type=&quot;checkbox&quot; class=&quot;input_boolean&quot; name=&quot;&#039;.$field_object-&gt;Field.&#039;&quot; value=&quot;1&quot; /&gt;&#039;;
        }

        if  (
            strpos($field_object-&gt;Type, &#039;int&#039;) !== false ||
            strpos($field_object-&gt;Type, &#039;varchar&#039;) !== false ||
            strpos($field_object-&gt;Type, &#039;float&#039;) !== false ||
            strpos($field_object-&gt;Type, &#039;decimal&#039;) !== false ||
            strpos($field_object-&gt;Type, &#039;double&#039;) !== false ||
            strpos($field_object-&gt;Type, &#039;real&#039;) !== false ||
            strpos($field_object-&gt;Type, &#039;date&#039;) !== false ||
            strpos($field_object-&gt;Type, &#039;time&#039;) !== false
            )
        {
            return &#039;&lt;input type=&quot;text&quot; class=&quot;input_varchar&quot; name=&quot;&#039;.$field_object-&gt;Field.&#039;&quot; value=&quot;&#039;.htmlentities($value).&#039;&quot; /&gt;&#039;;
        }

        if(strpos($field_object-&gt;Type, &#039;text&#039;) !== false)
        {
            return &#039;&lt;textarea class=&quot;input_text&quot; name=&quot;&#039;.$field_object-&gt;Field.&#039;&quot;&gt;&#039;.$value.&#039;&lt;/textarea&gt;&#039;;
        }

    }

    public static function PrettifyName($name)
    {
        return ucwords(str_replace(&#039;_&#039; , &#039; &#039;, $name));
    }

    // MySQL Specific
    public static function GetFields($class)
    {
        $primary_key_column = strtolower($class).&#039;_id&#039;;
        $table = DB_T_PREPEND.strtolower($class);

        $cmd = &quot;SHOW COLUMNS FROM &quot;.$table.&quot;&quot;;

        $result = mysql_query($cmd);
        while($row = mysql_fetch_object($result))
        {
            $cols[] = $row;
        }

        return $cols;;
    }

}
</pre>
<p>This helper class is simply used as an example for automating CRUD using Axis Entity Objects. We can easily modify the methods apply business rules for validating the object by providing that method in our &#8220;Fruit&#8221; class and calling its Validate() method. We can also adjust the methods for other databases.</p>
<p>That is our limitation with this example helper. Each database has different ways of parsing the columns of a table. This example was specific to MySQL.</p>
]]></content:encoded>
			<wfw:commentRss>http://jordansavant.com/programming-in-php-axis-entity-object-helper/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Programming in PHP: Axis Entity Objects</title>
		<link>http://jordansavant.com/programming-in-php-axis-entity-objects</link>
		<comments>http://jordansavant.com/programming-in-php-axis-entity-objects#comments</comments>
		<pubDate>Wed, 04 Jan 2012 04:48:49 +0000</pubDate>
		<dc:creator>Jordan Savant</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Projects]]></category>

		<guid isPermaLink="false">http://jordansavant.com/?p=363</guid>
		<description><![CDATA[During some spare time I developed an abstract ORM class that can be extended by entity classes that automatically implement the create, update and delete methods for the object&#8217;s table entry in a relational database. This is a work in &#8230; <a href="http://jordansavant.com/programming-in-php-axis-entity-objects">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>During some spare time I developed an abstract ORM class that can be extended by entity classes that automatically implement the create, update and delete methods for the object&#8217;s table entry in a relational database. This is a work in progress, but I will go through the existing version to explain.</p>
<p>The create, update, and delete methods can be called on any object that extends the AxisEntityObject class to perform the related operation on that instance. It will immediately remove, create or update the object related entry in the database using created SQL and PHP PDO. But also, each class inherits a static method that is the factory for the object type which requires only the primary key associated with an object to generate it.</p>
<p>Lets take a look at the interface.</p>
<pre class="brush: php; ">
&lt;?php
interface IAxisEntityObject{   
    public function Create();
    public static function Factory($primary_key, $custom_class_name = &#039;&#039;);
    public static function FactoryList($primary_keys, $custom_class_name = &#039;&#039;);
    public static function FactoryAll();       
    public function Update();
    public function Delete();
}
</pre>
<p>As you can see we require the defined methods and also require three types of factories that are common in ORM object generation. We can product all objects of a class, a single object by primary key, or a list based on an array of primary keys.</p>
<p>Here is the implementation of the abstract class.</p>
<pre class="brush: php; ">

abstract class AxisEntityObject implements IAxisEntityObject
{

    //////////////////////////////////
    // CUD METHODS
    ////////////////////////////////

    public function Create()
    {
        // We need to grab the current objects class before we call its functions
        // so that we can link to the related table and not to a table named after our abstract class

        $class = get_class($this);
        $primary_key_column = call_user_func(array($class, &#039;primaryKeyName&#039;), $class);
        $table = call_user_func(array($class, &#039;tableName&#039;), $class);

        $entry_fields = array();

        // Loop through each of the fields of the object instance
        // and look for any other properties that need to cascade the creation process

        foreach($this as $field =&gt; $value)
        {
            if($field != $primary_key_column)
            {
                if($value instanceof AxisEntityObject)
                {
                    $value-&gt;Create();
                }
                elseif(is_array($value))
                {
                    foreach($value as $array_value)
                    {
                        if($array_value instanceof AxisEntityObject)
                        {
                            // Cascade call all properties Create method if they are of the same class type
                            // recursive in nature

                            $array_value-&gt;Create();
                        }
                    }
                }
                elseif($this-&gt;$field != null)
                {
                    // Build our SQL

                    $k_sql .= $field.&#039;, &#039;;

                    $v_sql .= &#039;:&#039;.$field.&#039;, &#039;;

                    $entry_fields[$field] = $value;
                }
            }
        }

        // Use PHP PDO to persist the objects fields and complete the create method
        $cmd = &quot;INSERT INTO &quot;.$table.&quot; (&quot;.substr($k_sql, 0, -2).&quot;) VALUES (&quot;.substr($v_sql, 0, -2).&quot;)&quot;;

        $STH = $GLOBALS[&#039;DBH&#039;]-&gt;prepare($cmd);
        $STH-&gt;execute((array)$entry_fields);

        return $GLOBALS[&#039;DBH&#039;]-&gt;lastInsertId();
    }

    public function Update()
    {
        // Again for updates we need the class name that extends AxisEntityObjects
        $class = get_class($this);
        $primary_key_column = call_user_func(array($class, &#039;primaryKeyName&#039;), $class);
        $table = call_user_func(array($class, &#039;tableName&#039;), $class);

        // Cascade the update call to all properties that are also extend the abstract class

        if($this-&gt;$primary_key_column != &#039;&#039;)
        {

            foreach($this as $field =&gt; $value)
            {
                if($field != $primary_key_column)
                {
                    if($value instanceof AxisEntityObject)
                    {
                        $value-&gt;Update();
                    }
                    elseif(is_array($value))
                    {
                        foreach($value as $array_value)
                        {
                            if($array_value instanceof AxisEntityObject)
                            {
                                $array_value-&gt;Update();
                            }
                        }
                    }
                    elseif($value != null)
                    {
                        $v_sql .= $field . &#039; = :&#039;.$field.&#039;, &#039;;

                        $entry_fields[$field] = $value;
                    }
                }
            }

            // Persist the object changes
            $cmd = &quot;UPDATE &quot;.$table.&quot;  SET &quot;.substr($v_sql, 0, -2).&quot; WHERE &quot;.$primary_key_column.&quot; = &quot;.$this-&gt;$primary_key_column;

            $STH = $GLOBALS[&#039;DBH&#039;]-&gt;prepare($cmd);
            $STH-&gt;execute((array)$entry_fields);
        }
    }

    public function Delete()
    {
        $class = get_class($this);
        $primary_key_column = call_user_func(array($class, &#039;primaryKeyName&#039;), $class);
        $table = call_user_func(array($class, &#039;tableName&#039;), $class);

        if($this-&gt;$primary_key_column != &#039;&#039;)
        {
            $cmd = &quot;DELETE FROM &quot;.$table.&quot; WHERE &quot;.$primary_key_column.&quot; = &quot;.$this-&gt;$primary_key_column;

            $STH = $GLOBALS[&#039;DBH&#039;]-&gt;prepare($cmd);
            $STH-&gt;execute((array)$this);
        }
    }

    //////////////////////////////////
    // RETRIEVE METHODS
    ////////////////////////////////

    public static function Factory($primary_key, $custom_class_name = &#039;&#039;)
    {
        // Get our proper class name and table names
        if($custom_class_name != &#039;&#039;)
            $class = $custom_class_name;
        else
            $class = get_called_class();
        $primary_key_column = call_user_func(array($class, &#039;primaryKeyName&#039;), $class);
        $table = call_user_func(array($class, &#039;tableName&#039;), $class);

        // get table entry for object
        $cmd = &quot;SELECT
                    *
                FROM
                    `&quot;.$table.&quot;`
                WHERE
                    `&quot;.$primary_key_column.&quot;` = &#039;&quot;.$primary_key.&quot;&#039;&quot;;

        // Execute call
        $STH = $GLOBALS[&#039;DBH&#039;]-&gt;prepare($cmd);
        $STH-&gt;setFetchMode(PDO::FETCH_CLASS, $class);
        $STH-&gt;execute();
        $result = $STH-&gt;fetch(PDO::FETCH_CLASS);

        if($result == false)
            return null;

        return $result;
    }

    public static function FactoryAll()
    {
        // get the proper class
        $class = get_called_class();
        $primary_key_column = call_user_func(array($class, &#039;primaryKeyName&#039;), $class);
        $table = call_user_func(array($class, &#039;tableName&#039;), $class);

        $cmd = &quot;SELECT &quot;.$primary_key_column.&quot; FROM &quot;.$table;

        $STH = $GLOBALS[&#039;DBH&#039;]-&gt;prepare($cmd);
        $STH-&gt;execute();

        // Call our Factory method on all returned objects mapped
        while($row = $STH-&gt;fetch(PDO::FETCH_OBJ))
        {
            $list[] = call_user_func(array($class, &#039;Factory&#039;), $row-&gt;$primary_key_column, $class);
        }

        return $list;
    }

    public static function FactoryList($primary_keys, $custom_class_name = &#039;&#039;)
    {
        // get our proper class
        if($custom_class_name != &#039;&#039;)
            $class = $custom_class_name;
        else
            $class = get_called_class();
        $primary_key_column = call_user_func(array($class, &#039;primaryKeyName&#039;), $class);
        $table = call_user_func(array($class, &#039;tableName&#039;), $class);

        $in = &quot;(&#039;&quot;.implode(&quot;&#039;, &#039;&quot;, $primary_keys).&quot;&#039;)&quot;;

        // get table entries
        $cmd = &quot;SELECT
                    *
                FROM
                    `&quot;.$table.&quot;`
                WHERE
                    `&quot;.$primary_key_column.&quot;` IN &quot;.$in.&quot;
                ORDER BY
                    CASE
                    &quot;;
        foreach($primary_keys as $i =&gt; $v)
        {
            $cmd .= &quot; WHEN &quot;.$primary_key_column.&quot; = &quot;.$v.&quot; THEN &quot;.$i.&quot; &quot;;
        }

        $cmd .= &quot; END&quot;;

        // USE PDO to build the objects of the proper class

        $STH = $GLOBALS[&#039;DBH&#039;]-&gt;prepare($cmd);
        $STH-&gt;setFetchMode(PDO::FETCH_CLASS, $class);
        $STH-&gt;execute();

        while($row = $STH-&gt;fetch(PDO::FETCH_CLASS))
        {
            $list[] = $row;
        }

        return $list;
    }

    // These methods are used to map the table names and class names for the ORM logic
    protected static function primaryKeyName($class)
    {
        return call_user_func(array($class, &#039;underscoreFromCamelCase&#039;), $class) . &#039;_id&#039;;
    }

    protected static function tableName($class)
    {
        return DB_T_PREPEND . call_user_func(array($class, &#039;underscoreFromCamelCase&#039;), $class);
    }

    protected static function underscoreFromCamelCase($str)
    {
        $str[0] = strtolower($str[0]);
        $func = create_function(&#039;$c&#039;, &#039;return &quot;_&quot; . strtolower($c[1]);&#039;);

        return preg_replace_callback(&#039;/([A-Z])/&#039;, $func, $str);
    }
}
</pre>
<p>This class will perform ORM operations on an instance and can be used very simply in the following ways.</p>
<p>Lets extend this class with a normal entity class like Fruit.</p>
<h2>Entity Class Creation:</h2>
<pre class="brush: php; ">

class Fruit extends AxisEntityObject
{

}
</pre>
<p>Simple!</p>
<h2>Create:</h2>
<pre class="brush: php; ">

$fruit = new Fruit();
$fruit-&gt;fruit_name = &#039;Pineapple&#039;;
$fruit_id = $fruit-&gt;Create(); 
</pre>
<h2>Retrieve and Update:</h2>
<pre class="brush: php; ">

$fruit = Fruit::Factory(&#039;21&#039;); // 21 is our primary key id in the database.
</pre>
<p>Combine retrieval with updating for simple object updating.</p>
<pre class="brush: php; ">

$fruit = Fruit::Factory(&#039;21&#039;);
$fruit-&gt;name = &#039;Orange&#039;;
$fruit-&gt;Update();
</pre>
<h2>Delete:</h2>
<pre class="brush: php; ">

$fruit = Fruit::Factory(&#039;21&#039;); // 21 is our primary key id in the database.
$fruit-&gt;Delete();
</pre>
]]></content:encoded>
			<wfw:commentRss>http://jordansavant.com/programming-in-php-axis-entity-objects/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Programming in C++: Final Forecast</title>
		<link>http://jordansavant.com/programming-in-c-final-forecast</link>
		<comments>http://jordansavant.com/programming-in-c-final-forecast#comments</comments>
		<pubDate>Wed, 04 Jan 2012 04:24:11 +0000</pubDate>
		<dc:creator>Jordan Savant</dc:creator>
				<category><![CDATA[C++]]></category>
		<category><![CDATA[Projects]]></category>

		<guid isPermaLink="false">http://jordansavant.com/?p=361</guid>
		<description><![CDATA[Final Forecast is a networked terrain simulation video game developed using C++, the Ogre game libraries and the Boost C++ libraries. It utilizes threads, network communication, 3D graphics acceleration and similar game concepts. Designed by myself and my software engineering &#8230; <a href="http://jordansavant.com/programming-in-c-final-forecast">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Final Forecast is a networked terrain simulation video game developed using C++, the Ogre game libraries and the Boost C++ libraries. It utilizes threads, network communication, 3D graphics acceleration and similar game concepts. Designed by myself and my software engineering senior design team Final Forecast as presented in the University of Texas at Dallas Senior Design showcase for industry professionals and academic staff. Let me go over some of the methods employed and some of the code involved.</p>
<p>Developed for both the linux and windows platforms the code is separated into two different projects: the server and the client.</p>
<h2>The Server:</h2>
<p>More coming soon.</p>
]]></content:encoded>
			<wfw:commentRss>http://jordansavant.com/programming-in-c-final-forecast/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Case Study: Museum Works Audio Tours</title>
		<link>http://jordansavant.com/case-study-museum-works-audio-tours</link>
		<comments>http://jordansavant.com/case-study-museum-works-audio-tours#comments</comments>
		<pubDate>Wed, 04 Jan 2012 03:59:41 +0000</pubDate>
		<dc:creator>Jordan Savant</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Projects]]></category>

		<guid isPermaLink="false">http://jordansavant.com/?p=352</guid>
		<description><![CDATA[Museum Works Audio Tours is a company that provides multimedia presentations to captivate and interest museum visitors for exhibits of all types. Much of their presentation includes audio messages and ambient sounds to represent the exhibit to users of the &#8230; <a href="http://jordansavant.com/case-study-museum-works-audio-tours">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p><a href="http://jordansavant.com/wp-content/uploads/2012/01/museum-works-audio-tours.png"><img src="http://jordansavant.com/wp-content/uploads/2012/01/museum-works-audio-tours-300x220.png" alt="" title="museum-works-audio-tours" width="300" height="220" class="alignright size-medium wp-image-353" /></a>Museum Works Audio Tours is a company that provides multimedia presentations to captivate and interest museum visitors for exhibits of all types. Much of their presentation includes audio messages and ambient sounds to represent the exhibit to users of the museum.</p>
<p>Museum Works Audio Tours contracted <a href="http://www.angelwirecreative.com" target="_blank">Angelwire Creative</a> to build a media management back end system for their existing web site. I was brought in to design and develop the tools they needed a management system that allowed them to upload audio files of type mp3, wav, or aiff. They as well needed to correlate a visual image with each audio file for their viewers. The management system needed to present the files of their choosing to the visitors of their site and present them with a UI tool for navigating the audio files each with their own cover image.</p>
<p>This was incorporated for them through a back end management system that is still being used today.</p>
<h2>Technologies Employed:</h2>
<ul>
<li>PHP</li>
<li>Quicktime Player</li>
<li>PHP GD Library</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://jordansavant.com/case-study-museum-works-audio-tours/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Case Study: Xeta Telecommunications</title>
		<link>http://jordansavant.com/case-study-xeta-telecommunications</link>
		<comments>http://jordansavant.com/case-study-xeta-telecommunications#comments</comments>
		<pubDate>Wed, 04 Jan 2012 03:37:06 +0000</pubDate>
		<dc:creator>Jordan Savant</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Projects]]></category>

		<guid isPermaLink="false">http://jordansavant.com/?p=335</guid>
		<description><![CDATA[Xeta Telecommunications was in need of an eCommerce solution customized to their own specific business model. This meant an eCommerce store that allowed for a tier based pricing and allocating users into particular pricing brackets. It also meant a private &#8230; <a href="http://jordansavant.com/case-study-xeta-telecommunications">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p><a href="http://jordansavant.com/wp-content/uploads/2012/01/coLogo1.jpg"><img class="alignright size-medium wp-image-338" title="xetaLogo" src="http://jordansavant.com/wp-content/uploads/2012/01/coLogo1-300x130.jpg" alt="" width="300" height="130" /></a>Xeta Telecommunications was in need of an <strong>eCommerce solution</strong> customized to their own specific business model. This meant an eCommerce store that allowed for a <strong>tier based pricing</strong> and allocating users into particular pricing brackets. It also meant a <strong>private web store</strong> that only specific clientele could access. All of this was needed and it was needed quickly and within a limited budget. I was contracted through <a href="http://www.angelwirecreative.com" target="_blank">Angelwire Creative</a> to help achieve this goal.</p>
<p>To accommodate this project a customized version of <strong>osCommerce</strong> was employed that would involve a heavy modification of the core application. Since osCommerce was an open source project, it allowed myself to make the needed changes to the code base for Xeta, while at the same time eliminating the need for developing all the other necessary eCommerce tools such as user management, product management, shopping carts, and payment APIs.</p>
<h2>Strike Iron</h2>
<p><img class="alignright size-medium wp-image-349" title="strikeiron" src="http://jordansavant.com/wp-content/uploads/2012/01/strikeiron1-300x143.png" alt="" width="300" height="143" />Portions of the eCommerce store leveraged the powerful API provided by Strike Iron at <a title="strikeiron.com" href="http://www.strikeiron.com">www.strikeiron.com</a>. Their API allowed for customer zip code look-ups to determine the user&#8217;s zip code based upon their designated street address, and also resolve possible city conflictions regarding zip codes that overlap zip code boundaries. It also allowed for validating customer addresses, phone numbers, and was used to calculated tax rates based on customer location.</p>
<h2>Technologies Employed:</h2>
<ul>
<li>PHP &amp; MySQL</li>
<li><a title="oscommerce.com" href="http://www.oscommerce.com/" target="_blank">osCommerce</a></li>
<li>JavaScript</li>
<li><a href="http://www.strikeiron.com/Catalog/SampleCode/" target="_blank">Strike Iron API</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://jordansavant.com/case-study-xeta-telecommunications/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Case Study: Nations Home Warranty</title>
		<link>http://jordansavant.com/case-study-nations-home-warranty</link>
		<comments>http://jordansavant.com/case-study-nations-home-warranty#comments</comments>
		<pubDate>Wed, 04 Jan 2012 03:25:59 +0000</pubDate>
		<dc:creator>Jordan Savant</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Projects]]></category>

		<guid isPermaLink="false">http://jordansavant.com/?p=322</guid>
		<description><![CDATA[Nations Home Warranty is a Texas based home warranty company servicing native Texans and Oklahomans with outstanding home warranty services. Much of their great customer interaction is supported by a well-built and maintained application process on their website home-warranty.com. The &#8230; <a href="http://jordansavant.com/case-study-nations-home-warranty">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p><strong><a href="http://jordansavant.com/wp-content/uploads/2012/01/main-page.png"><img class="alignright size-medium wp-image-323" title="main-page" src="http://jordansavant.com/wp-content/uploads/2012/01/main-page-294x300.png" alt="" width="294" height="300" /></a>Nations Home Warranty</strong> is a Texas based home warranty company servicing native Texans and Oklahomans with outstanding home warranty services. Much of their great customer interaction is supported by a <strong>well-built and maintained application process</strong> on their website <a title="home-warranty.com" href="http://www.home-warranty.com" target="_blank">home-warranty.com</a>.</p>
<p>The Nations Home Warranty was in a serious need up upgrade and contemporizing to capture their visitors attention and provide them with tools for managing their home warranty contacts. I was employed through <a href="http://www.angelwirecreative.com" target="_blank">Angelwire Creative</a> to redesign an existing but dated application process that had become un-maintainable by their staff. Much of the PHP was designed for PHP 3 and needed a serious redesign if it were to survive a single server update.</p>
<p>The application process was not only streamlined for PHP 4 at the time, it was also <strong>rebuilt to be modular with adjustable pricing and pricing packages for their various contracts</strong>. It also was integrated into a user toolkit that users could use to review their existing contracts and update their contact information. As well, the application process was <strong>built to service individuals who spoke both English and Spanish</strong> as a first language.</p>
<p><a href="http://jordansavant.com/wp-content/uploads/2012/01/applicationA.png"><img class="alignleft size-medium wp-image-327" title="applicationA" src="http://jordansavant.com/wp-content/uploads/2012/01/applicationA-300x204.png" alt="" width="300" height="204" /></a>This was made possible by refactoring the site&#8217;s text into <strong>manageable language files</strong> that could be swapped out as the user defined their language. It would allow for the expansion of any number of languages as well.</p>
<p>An <strong>application management center</strong> was developed for the Nations Home Warranty staff to review new applications, archive or remove outdated applications, and contact their customer base. As well, support was given for the staff to issue newsletters to their subscribed email base.</p>
<p>&nbsp;</p>
<hr />
&nbsp;</p>
<p><a href="http://jordansavant.com/wp-content/uploads/2012/01/main.png"><img class="aligncenter size-full wp-image-329" title="main" src="http://jordansavant.com/wp-content/uploads/2012/01/main.png" alt="" width="960" height="881" /></a></p>
]]></content:encoded>
			<wfw:commentRss>http://jordansavant.com/case-study-nations-home-warranty/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Case Study: The Voice of Pro Equine Group</title>
		<link>http://jordansavant.com/case-study-the-voice-of-pro-equine-group</link>
		<comments>http://jordansavant.com/case-study-the-voice-of-pro-equine-group#comments</comments>
		<pubDate>Wed, 04 Jan 2012 02:38:15 +0000</pubDate>
		<dc:creator>Jordan Savant</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Projects]]></category>

		<guid isPermaLink="false">http://jordansavant.com/?p=305</guid>
		<description><![CDATA[The Voice of Pro Equine group was a project developed for the internal use of Pro Equine Group of Dallas, TX. I was contracted to develop this application through Angelwire Creative. It accomplished many goals that the company needed to &#8230; <a href="http://jordansavant.com/case-study-the-voice-of-pro-equine-group">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>The Voice of Pro Equine group was a project developed for the internal use of Pro Equine Group of Dallas, TX. I was contracted to develop this application through <a href="http://www.angelwirecreative.com" target="_blank">Angelwire Creative</a>. It accomplished many goals that the company needed to complete and is in active use today.</p>
<h2>The Problem:</h2>
<p><a href="http://jordansavant.com/wp-content/uploads/2012/01/createCDUField.png"><img class="alignright size-medium wp-image-312" title="createCDUField" src="http://jordansavant.com/wp-content/uploads/2012/01/createCDUField-300x197.png" alt="" width="300" height="197" /></a>Pro Equine Group was a parent company over several smaller companies that sold and managed products regarding equestrian and riding uses. Each of these smaller companies managed and oversaw their own repository of customer contacts for use in future marketing and sales information. <strong>The problem lay in the fact that many of these customers purchased products among several of their child companies at each time</strong>, and since each child company oversaw their own database of customer information, linking and managing the customers was an impossibility.</p>
<p><strong>Each child company would store their customer database using a different format and different structure.</strong> Some stored their information use Excel, others a database. All stored them differently.</p>
<h2>The Solution:</h2>
<p><a href="http://jordansavant.com/wp-content/uploads/2012/01/usermanagement.png"><img class="alignright size-medium wp-image-314" title="usermanagement" src="http://jordansavant.com/wp-content/uploads/2012/01/usermanagement-300x197.png" alt="" width="300" height="197" /></a>I developed a system for managing not only their child companies, but also created a powerful series of tools that alleviated the separated customer databases. A powerful upload tool allowed their user base to <strong>upload any CSV of any format</strong> containing customers and any other secondary customer information into a single database that Pro Equine Group could manage and use for marketing.</p>
<p>This was accomplished by developing a front-end tool that allowed users of a specific user type the power to <strong>create custom columns in a report table</strong> within a single database. They could designate each of these columns to contain a different type of data and provide a related description and name. These columns represented other customer information such as receipt information, age ranges etc.</p>
<p><a href="http://jordansavant.com/wp-content/uploads/2012/01/querybuilder.png"><img class="alignleft size-medium wp-image-318" title="querybuilder" src="http://jordansavant.com/wp-content/uploads/2012/01/querybuilder-266x300.png" alt="" width="266" height="300" /></a>In correlation to this, a powerful upload tool <strong>allowed them to map any columns in a CSV to the columns defined in the database</strong> table. These mappings could be saved for re-use by the user and could be shared across the chile company to which that user belonged.</p>
<p>Uploading the CSV against this mapping would send the information through a filtering system that would <strong>recognize duplicated customers</strong> within the upload and would either mark that entry as &#8220;to merge&#8221;, &#8220;conflicted&#8221; or &#8220;matched&#8221;. <strong>Each option resulted in a protocol</strong> that could allow administrators to handle the confictions or merging process.</p>
<p>In addition to the upload procedure, a tool was developed to present a <strong>Graphical User Interface to the user that would allow them to shape and create their own queries</strong> into the uploaded customer database. The results would print in an HTML tabular format with support for downloading into Excel. These reports could be saved in the form of &#8220;campaigns&#8221; that would be re-usable and re-reportable by users for marketing usage or anything desired.</p>
<p>These tools allowed Pro Equine group the ability to overcome their separated customer database problems with ease. But alongside of this solution a fully functioning user management, customer search tool, and company management tool allowed Pro Equine group to really manage their business better than before.</p>
<h2>Technologies Employed:</h2>
<ul>
<li>PHP &#038; MySQL</li>
<li>CSV parsing</li>
<li>PHP Mailer</li>
<li>Microsoft Excel</li>
<li>JavaScript &#038; jQuery</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://jordansavant.com/case-study-the-voice-of-pro-equine-group/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Linux Tools &amp; Tricks: Compressing and Decompressing TAR.GZ</title>
		<link>http://jordansavant.com/linux-tools-tricks-compressing-and-decompressing-tar-gz</link>
		<comments>http://jordansavant.com/linux-tools-tricks-compressing-and-decompressing-tar-gz#comments</comments>
		<pubDate>Tue, 20 Dec 2011 18:35:50 +0000</pubDate>
		<dc:creator>Jordan Savant</dc:creator>
				<category><![CDATA[Linux]]></category>

		<guid isPermaLink="false">http://jordansavant.com/?p=301</guid>
		<description><![CDATA[Compress: tar -zcvf [filename].tar.gz [directory] Decompress: tar -xzvf [filename].tar.gz]]></description>
			<content:encoded><![CDATA[<p>Compress:</p>
<pre class="brush: powershell; ">

tar -zcvf [filename].tar.gz [directory]
</pre>
<p>Decompress:</p>
<pre class="brush: powershell; ">

tar -xzvf [filename].tar.gz
</pre>
]]></content:encoded>
			<wfw:commentRss>http://jordansavant.com/linux-tools-tricks-compressing-and-decompressing-tar-gz/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Linux Tools &amp; Tricks: Move All Files But One</title>
		<link>http://jordansavant.com/linux-tools-tricks-move-all-files-but-one</link>
		<comments>http://jordansavant.com/linux-tools-tricks-move-all-files-but-one#comments</comments>
		<pubDate>Sat, 17 Dec 2011 19:06:43 +0000</pubDate>
		<dc:creator>Jordan Savant</dc:creator>
				<category><![CDATA[Linux]]></category>

		<guid isPermaLink="false">http://jordansavant.com/?p=299</guid>
		<description><![CDATA[find ~/Linux/Old -maxdepth 1 -mindepth 1 -not -name Tux.png -print0 &#124; xargs -0 mv -t ~/Linux/New -maxdepth 1 makes it not search recursively. If you only care about files, you can say -type f. -mindepth 1 makes it not include &#8230; <a href="http://jordansavant.com/linux-tools-tricks-move-all-files-but-one">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<pre class="brush: powershell; ">

find ~/Linux/Old -maxdepth 1 -mindepth 1 -not -name Tux.png -print0 | xargs -0 mv -t ~/Linux/New
</pre>
<p>-maxdepth 1 makes it not search recursively. If you only care about files, you can say -type f. -mindepth 1 makes it not include the ~/Linux/Old path itself into the result. Works with any filenames, including with those that contain embedded newlines.</p>
<p>One comment notes that the mv -t option is a probably GNU extension. For systems that don&#8217;t have it: </p>
<pre class="brush: powershell; ">

find ~/Linux/Old -maxdepth 1 -mindepth 1 -not -name Tux.png \ -exec mv &#039;{}&#039; ~/Linux/New \;
</pre>
]]></content:encoded>
			<wfw:commentRss>http://jordansavant.com/linux-tools-tricks-move-all-files-but-one/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Programming In Shell Script: Count Files</title>
		<link>http://jordansavant.com/programming-in-shell-script-count-files</link>
		<comments>http://jordansavant.com/programming-in-shell-script-count-files#comments</comments>
		<pubDate>Wed, 14 Dec 2011 14:48:30 +0000</pubDate>
		<dc:creator>Jordan Savant</dc:creator>
				<category><![CDATA[Projects]]></category>
		<category><![CDATA[Shell]]></category>

		<guid isPermaLink="false">http://jordansavant.com/?p=287</guid>
		<description><![CDATA[Here is a sample shell script program that simply counts the number of regular files, directories and symbolic links within a directory, but excludes counting items within subdirectories. # The script accepts a directory and produces output that tells how &#8230; <a href="http://jordansavant.com/programming-in-shell-script-count-files">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Here is a sample shell script program that simply counts the number of regular files, directories and symbolic links within a directory, but excludes counting items within subdirectories.</p>
<pre class="brush: powershell; ">

# The script accepts a directory and produces output that tells how many regular files, directories, and symbolic links are in the directory (exclude subdirectories).
# The words in the output are singular or plural depending on the count (e.g. 1 link, 2 links).  Make sure the directory exists.
# Use the current directory if none was provided.
# Print out a &quot;Usage&quot; message if the user gave more than one argument.

# Syntax:   countfiles.sh directory

#!/bin/bash

#usage
directory=$1
[ $# -eq 0 ] &amp;&amp; directory=$PWD
[ $# -gt 1 ] &amp;&amp; { echo &quot;Usage: countfiles.sh requires one directory as a parameter.&quot;; exit 1; }

dirs=0;files=0;links=0
# take directory parameter and check if it exists
# $0 is the directory
[ -d $directory ] || { echo &quot;Directory specified either does not exist or is of a different file type.&quot;; exit 1; }

# loop through files in directory
for file in $directory/*;
do
	[ -d &quot;$file&quot; ] &amp;&amp; dirs=`expr $dirs + 1`
	[ -f &quot;$file&quot; ] &amp;&amp; files=`expr $files + 1`
	[ -h &quot;$file&quot; ] &amp;&amp; links=`expr $links + 1`
done

echo &quot;Directory $directory contains:&quot;;
if [ $dirs -eq 1 ]; then
	echo &quot;$dirs directory&quot;
else
	echo &quot;$dirs directories&quot;
fi
if [ $files -eq 1 ]; then
	echo &quot;$files file&quot;
else
	echo &quot;$files files&quot;
fi
if [ $links -eq 1 ]; then
	echo &quot;$links symbolic link&quot;
else
	echo &quot;$links symbolic links&quot;
fi

exit 0
</pre>
<p>Here is a test:</p>
<pre>
jordan@jordan-VirtualBox:~/Desktop$ mkdir testDir
jordan@jordan-VirtualBox:~/Desktop$ cd testDir
jordan@jordan-VirtualBox:~/Desktop/testDir$ touch regular_file
jordan@jordan-VirtualBox:~/Desktop/testDir$ mkdir directory
jordan@jordan-VirtualBox:~/Desktop/testDir$ ln -s ~/Desktop/testDir/regular_file symbolic_link
jordan@jordan-VirtualBox:~/Desktop/testDir$ ls -l
total 4
drwxr-xr-x 2 jordan jordan 4096 2011-12-14 11:10 directory
-rw-r--r-- 1 jordan jordan    0 2011-12-14 11:10 regular_file
lrwxrwxrwx 1 jordan jordan   41 2011-12-14 11:11 symbolic_link -> /home/jordan/Desktop/testDir/regular_file
jordan@jordan-VirtualBox:~/Desktop/testDir$ cd ../
jordan@jordan-VirtualBox:~/Desktop$ ./countfiles.sh testDir
Directory testDir contains:
1 directory
2 files
1 symbolic link
</pre>
<p>After creating our test folder, the outputs of count files performs well. Even though a link is different than a regular file, it is still a file all the same, so we have a count of 2 files in our report.</p>
<p>Extremely simple but extremely useful to have as a nice command line tool. Make an alias for it in your Linux environment and simply run &#8220;countfiles.sh&#8221;. If the directory argument is blank, it will use the current directory.</p>
<p>Download: <a href='http://jordansavant.com/wp-content/uploads/2011/12/countfiles.zip'>countfiles.zip</a></p>
]]></content:encoded>
			<wfw:commentRss>http://jordansavant.com/programming-in-shell-script-count-files/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
