<?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>One Mo' Gin &#187; Catalyst</title>
	<atom:link href="http://www.onemogin.com/blog/category/code/catalyst/feed" rel="self" type="application/rss+xml" />
	<link>http://www.onemogin.com/blog</link>
	<description>Sometimes once isn't enough.  Perl programming plus whatever else piques my interest.</description>
	<lastBuildDate>Tue, 08 Sep 2009 17:25:32 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.1</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Authenticating Against Active Directory with Catalyst</title>
		<link>http://www.onemogin.com/blog/639-authenticating-against-active-directory-with-catalyst</link>
		<comments>http://www.onemogin.com/blog/639-authenticating-against-active-directory-with-catalyst#comments</comments>
		<pubDate>Fri, 15 May 2009 00:09:43 +0000</pubDate>
		<dc:creator>gphat</dc:creator>
				<category><![CDATA[Catalyst]]></category>
		<category><![CDATA[Code]]></category>
		<category><![CDATA[Languages]]></category>
		<category><![CDATA[Perl]]></category>
		<category><![CDATA[Windows]]></category>
		<category><![CDATA[Work]]></category>

		<guid isPermaLink="false">http://www.onemogin.com/blog/?p=639</guid>
		<description><![CDATA[One of the more entertaining part of working in e-commerce is dealing with PCI compliance.  I say interesting because the standard is a mix of good things and inane things.  Regardless, it&#8217;s required.  One of the sections deals with authentication and authorization.  We&#8217;ve traditionally done that sort of business internally, but [...]]]></description>
			<content:encoded><![CDATA[<p>One of the more entertaining part of working in e-commerce is dealing with <a href="http://en.wikipedia.org/wiki/PCI_DSS">PCI compliance</a>.  I say interesting because the standard is a mix of good things and inane things.  Regardless, it&#8217;s required.  One of the sections deals with authentication and authorization.  We&#8217;ve traditionally done that sort of business internally, but the newest PCI standards gave us quite a few requirements that we didn&#8217;t feel like adding.  Instead, we opted to offload that functionality onto our Windows machines.  We already had some experience with this, as our internal <a href="http://trac.edgewall.org/">Trac</a> talks to Active Directory to ease our administration when interfacing with the other departments.</p>
<p>Enough backstory.  I had some hassle getting <a href="http://search.cpan.org/perldoc?Catalyst::Authentication::Store::LDAP">Catalyst::Authentication::Store::LDAP</a> working with Active Directory.  I wanted both authentication and roles, so here&#8217;s what I ended up with:</p>
<pre>
Plugin::Authentication:
    default_realm: members
    realms:
        members:
            credential:
                class: Password
                password_field: password
                password_type: self_check
            store:
                class: LDAP
                ldap_server: dc1:389
                ldap_server_options:
                    timeout: 30
                binddn: cn=SomeAccountYouSetup,ou=Accounts,dc=domain,dc=com
                bindpw: password
                user_basedn: ou=Accounts,dc=domain,dc=com
                user_filter: (userPrincipalName=%s)
                user_field: mail
                use_roles: 1
                role_basedn: ou=Groups,dc=domain,dc=com
                role_filter: (member=%s)
                role_scope: sub
                role_field: name
                role_value: dn
                role_search_as_user: 0
                role_search_options:
                    deref: always
</pre>
<p>I&#8217;m not really participating in <a href="http://www.shadowcat.co.uk/blog/matt-s-trout/iron-man/">Matt&#8217;s Iron Man</a> but the flurry of Perl posting does leave me feeling a bit guilty for not saying a bit more about my language of choice.</p>
<p><b>UPDATE:</b> I&#8217;ve changed the configuration a bit to show what you need to change.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.onemogin.com/blog/639-authenticating-against-active-directory-with-catalyst/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Come Work For Us</title>
		<link>http://www.onemogin.com/blog/596-come-work-for-us</link>
		<comments>http://www.onemogin.com/blog/596-come-work-for-us#comments</comments>
		<pubDate>Wed, 24 Dec 2008 02:32:42 +0000</pubDate>
		<dc:creator>gphat</dc:creator>
				<category><![CDATA[Catalyst]]></category>
		<category><![CDATA[Code]]></category>
		<category><![CDATA[General]]></category>
		<category><![CDATA[Languages]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[Operating Systems]]></category>
		<category><![CDATA[Perl]]></category>
		<category><![CDATA[Useless Information]]></category>
		<category><![CDATA[Work]]></category>

		<guid isPermaLink="false">http://www.onemogin.com/blog/?p=596</guid>
		<description><![CDATA[I work for magazines.com and we are looking to add to our team!
We&#8217;re a Perl shop, located in Franklin, Tennessee.  We sell magazine subscriptions online.  This year we&#8217;ve got a lot to do and I&#8217;m looking to add some developers to our ranks.  I&#8217;m not sure how many yet, but I can [...]]]></description>
			<content:encoded><![CDATA[<p>I work for <a href="http://www.magazines.com">magazines.com</a> and we are looking to add to our team!</p>
<p>We&#8217;re a Perl shop, located in <a href="http://maps.google.com/maps?f=q&#038;hl=en&#038;geocode=&#038;q=franklin,+tn&#038;sll=37.0625,-95.677068&#038;sspn=46.226656,78.134766&#038;ie=UTF8&#038;ll=35.958556,-86.801949&#038;spn=0.185637,0.305214&#038;z=12">Franklin, Tennessee</a>.  We sell magazine subscriptions online.  This year we&#8217;ve got a <em>lot</em> to do and I&#8217;m looking to add some developers to our ranks.  I&#8217;m not sure how many yet, but I can give the following details:</p>
<ul>
<li><b>Telecommuters are welcome.</b></>
<li>&#8220;New&#8221; code: Catalyst, DBIx::Class, Moose and all those things.</li>
<li>2009 Projects include two major &#8220;new&#8221; projects plus maintenance and refactoring in older applications.  Lots of niches to fill.  We&#8217;ll find the right one for you.</li>
<li>Apache, MySQL and Linux.</li>
<li>Conferences!  Number depends on schedule and work to be done.</li>
</ul>
<p>We aren&#8217;t looking for a <em>particular</em> job level. I&#8217;m interested in juniors to seniors.  The candidates we choose will depend on the choices we have.  If you are interested then drop an email to me via cwatson at magazines dot com.</p>
<p>I&#8217;m really excited about our work in 2009.  I&#8217;m opening the year with two talks at the <a href="http://perloasis.org/opw2009/">Orlando Perl Workshop</a> and a commitment to work with the Enlightened Perl Organisation.  I&#8217;ll eventually post this opportunity on <a href="http://jobs.perl.org/">jobs.perl.org</a> but wanted to start here.  Give me a shout!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.onemogin.com/blog/596-come-work-for-us/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Nope, I&#8217;m Not Dead</title>
		<link>http://www.onemogin.com/blog/589-nope-im-not-dead</link>
		<comments>http://www.onemogin.com/blog/589-nope-im-not-dead#comments</comments>
		<pubDate>Thu, 04 Dec 2008 00:14:20 +0000</pubDate>
		<dc:creator>gphat</dc:creator>
				<category><![CDATA[Catalyst]]></category>
		<category><![CDATA[Code]]></category>
		<category><![CDATA[Useless Information]]></category>
		<category><![CDATA[Work]]></category>

		<guid isPermaLink="false">http://www.onemogin.com/blog/?p=589</guid>
		<description><![CDATA[I recently rejoined my team at magazines.com and have been pretty busy getting back into the groove there.  It&#8217;s a busy place in Q4, so side stuff has taken a back seat.  Well, that&#8217;s mostly WoW&#8217;s fault.
While I&#8217;m at it, if you are a LAMP System Administrator in Nashville (or nearby) and are [...]]]></description>
			<content:encoded><![CDATA[<p>I recently rejoined my team at <a href="http://www.magazines.com">magazines.com</a> and have been pretty busy getting back into the groove there.  It&#8217;s a busy place in Q4, so side stuff has taken a back seat.  Well, that&#8217;s mostly <a href="http://www.worldofwarcraft.com">WoW</a>&#8217;s fault.</p>
<p>While I&#8217;m at it, if you are a LAMP System Administrator in Nashville (or nearby) and are looking for a great opportunity, drop an email to cwatson at magazines dot com!</p>
<p>On a side note, my <a href="http://www.catalystframework.org/calendar/2008/3">first entry</a> of the <a href="http://www.catalystframework.org/calendar/2008/">2008 Catalyst Advent Calendar</a> went up today.  Enjoy!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.onemogin.com/blog/589-nope-im-not-dead/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>An Introduction to Graphics::Primitive</title>
		<link>http://www.onemogin.com/blog/584-an-introduction-to-graphicsprimitive</link>
		<comments>http://www.onemogin.com/blog/584-an-introduction-to-graphicsprimitive#comments</comments>
		<pubDate>Thu, 04 Sep 2008 22:33:22 +0000</pubDate>
		<dc:creator>gphat</dc:creator>
				<category><![CDATA[Catalyst]]></category>
		<category><![CDATA[Chart::Clicker]]></category>
		<category><![CDATA[Code]]></category>
		<category><![CDATA[General]]></category>
		<category><![CDATA[Languages]]></category>
		<category><![CDATA[Perl]]></category>
		<category><![CDATA[Work]]></category>

		<guid isPermaLink="false">http://www.onemogin.com/blog/?p=584</guid>
		<description><![CDATA[It&#8217;s been on the CPAN for a few weeks, but I&#8217;ve not taken the time to pontificate about what exactly Graphics::Primitive and its cadre of helpers are.]]></description>
			<content:encoded><![CDATA[<p>It&#8217;s been <a href="http://search.cpan.org/dist/Graphics-Primitive/">on the CPAN</a> for a few weeks, but I&#8217;ve not taken the time to pontificate about what exactly Graphics::Primitive and its cadre of helpers are.</p</p>
<h2>Backstory</h2>
<p>I started working on <a href="http://www.onemogin.com/clicker">Chart::Clicker</a> quite a while back.  I&#8217;d just come from a job as a senior Java developer and still had <a href="http://en.wikipedia.org/wiki/Abstract_Window_Toolkit">AWT</a> and <a href="http://en.wikipedia.org/wiki/Swing_(Java)">Swing</a> on the brain.  I&#8217;d developed a custom charting package in perl a few months before but wasn&#8217;t happy with the results.  I sought out a solid charting package to emulate and was heavily inspired by <a href="http://www.jfree.org/jfreechart/">JFreeChart</a>.  One of the side effects of this was my disappointment with the availability of general graphics packages on <a href="http://www.cpan.org">the CPAN</a>.  I was jealous of the simple classes in Java that reduced a lot of the work in making graphics: Point, Rectangle, Color and more.</p>
<p>I released Chart::Clicker and was happy.  I had emulated a lot of the ideas inside Clicker, writing general Component, Font, Color and Border classes, to name a few.  As time went by and people began using Clicker it because clear to me that these concepts could be generalized and turned into a general framework for creating graphics.  Thus became Graphics::Primitive.</p>
<h2>Enter Graphics::Primitive</h2>
<p>Graphics::Primitive is a collection of objects that allow you build a 2d &#8220;scene&#8221;.  The building block of these scenes is a <a href="http://search.cpan.org/perldoc?Graphics::Primitive::Component">Component</a>.  It has a width and height, colors (fore and back), borders, insets and padding.  A <a href="http://search.cpan.org/perldoc?Graphics::Primitive::Container">Container</a> builds on Component and yields a component that can contain other components.  To allow for more than plain ol&#8217; boxes Graphics::Primitive provides <a href="http://search.cpan.org/perldoc?Graphics::Primitive::TextBox">TextBox</a>, <a href="http://search.cpan.org/perldoc?Graphics::Primitive::Canvas">Canvas</a> and <a href="http://search.cpan.org/perldoc?Graphics::Primitive::Image">Image</a>.  While these entities are all pretty simple, but you can create complex results by nesting them.</p>
<h2>Creating Output</h2>
<p>Graphics::Primitive is really just a data structure.  It doesn&#8217;t actually do any drawing.  Drawing is done by Drivers.  The only driver at present is <a href="http://search.cpan.org/perldoc?Graphics::Primitive::Driver::Cairo">Cairo</a>.  It makes a great first driver, however, as it provides PDF, PostScript, PNG and SVG output.</p>
<h2>Layout</h2>
<p>Graphics::Primitive also doesn&#8217;t concern itself with laying out your components.  Graphics::Primitive will leave components wherever you put them if left to its own devices.  To handle automatic layout management I created <a href="http://search.cpan.org/perldoc?Layout::Manager">Layout::Manager</a>.  As you add components to a container you can provide constraints for them.  Then you can ask an instance of Layout::Manager to &#8220;layout&#8221; your container (and any containers contained in it).  This concept is borrowed from Java&#8217;s <a href="http://java.sun.com/docs/books/tutorial/uiswing/layout/using.html">layout managers</a>. It is worth noting that each container has it&#8217;s own Layout::Manager so you can choose the one that is most fitting for the look you desire.</p>
<h2>Benefits</h2>
<p>Graphics::Primitive allows you to separate your data from your presentation.  Creating an artifact in Graphics::Primitive allows you to change the output format.  Need a PDF and a PNG?  There&#8217;s no reason to rely on a conversion tool or a separate rendering path.  Simply clone the component to pass it to each driver.</p>
<h2>What Can You Do With it?</h2>
<p>The aforementioned Chart::Clicker is made using Graphics::Primitive.   You can look over <a href="http://www.onemogin.com/clicker/examples">examples of its output</a>.  The examples are all pngs but any of those can be converted to any of the formats supported by the <a href="http://www.cairographics.org/">Cairo</a> driver by changing a single parameter.</p>
<p>There is a <a href="http://www.catalystframework.org/">Catalyst</a> view, which I released <a href="http://search.cpan.org/perldoc?Catalyst::Helper::View::Graphics::Primitive">onto CPAN today</a>.  This allows you to serve your components via HTTP.</p>
<p><a href="http://search.cpan.org/dist/Document-Writer/">Document::Writer</a> aims to abstract the underlying Graphics::Primitive components into an API friendly to creating documents.  It will likely change quite a bit as I refine the ideas and increase underlying features.</p>
<h2>Supporting Cast</h2>
<p>I created a handful of other modules in an effort to reduce the work others might do when building similar code.</p>
<p><a href="http://search.cpan.org/dist/Graphics-Color/">Graphics::Color</a> provides simple objects for various color spaces.  I&#8217;ve got a list of color spaces to add, as well as conversion routines.</p>
<p><a href="http://search.cpan.org/dist/Geometry-Primitive/">Geometry::Primitive</a> provides simple geometry entities such as Point, Circle and Rectangle.  These objects serve as the base for Graphics::Primitive.</p>
<h2>Future Plans</h2>
<p>I&#8217;m currently sitting on code that allows serialization of a Graphic::Primitive scene using <a href="http://search.cpan.org/perldoc?MooseX::Storage">MooseX::Storage</a>, but some API conflicts are stopping me from releasing until I work them out.</p>
<p>Document::Writer will be getting lots of new features as I back out a lot of my crappy text code for a more robust text-layout engine based on <a href="http://www.pango.org/">Pango</a>.  There are supposedly bindings coming for perl that are not tied to GTK+.</p>
<h2>Conclusion</h2>
<p>Graphics::Primitive has been a lot of fun.  If I&#8217;d known what I was getting into I probably would&#8217;ve run away screaming.  There have been many nights that I couldn&#8217;t sleep because a problem was rolling around my brain and I had to get up and hack on it for a few hours.</p>
<p>Please check it out and feel free to hit me up with ideas and suggestions.  I&#8217;ll be giving a talk, hopefully, at <a href="http://pghpw.org/ppw2008/">PPW 2008</a>.  The presentation itself is made in Graphics::Primitive, just for extra oomph.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.onemogin.com/blog/584-an-introduction-to-graphicsprimitive/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Announcing Osgood: An Event Repository</title>
		<link>http://www.onemogin.com/blog/579-announcing-osgood-an-event-repository</link>
		<comments>http://www.onemogin.com/blog/579-announcing-osgood-an-event-repository#comments</comments>
		<pubDate>Sat, 01 Mar 2008 14:04:01 +0000</pubDate>
		<dc:creator>gphat</dc:creator>
				<category><![CDATA[Catalyst]]></category>
		<category><![CDATA[General]]></category>
		<category><![CDATA[Languages]]></category>
		<category><![CDATA[Perl]]></category>
		<category><![CDATA[Useless Information]]></category>
		<category><![CDATA[Work]]></category>

		<guid isPermaLink="false">http://www.onemogin.com/blog/579-announcing-osgood-an-event-repository.html</guid>
		<description><![CDATA[Yesterday I released Osgood::Client and today, after realizing I had botched the upload, Osgood::Server.  Unfortunately the documentation is a little thin, so I&#8217;ll take this opportunity to both inform the world and the module of it&#8217;s purpose.
Osgood is a passive, persistent, stateless event repository.  The current docs say queue rather than repository but [...]]]></description>
			<content:encoded><![CDATA[<p>Yesterday I released <a href="http://search.cpan.org/perldoc?Osgood::Client">Osgood::Client</a> and today, after realizing I had botched the upload, Osgood::Server.  Unfortunately the documentation is a little thin, so I&#8217;ll take this opportunity to both inform the world and the module of it&#8217;s purpose.</p>
<p>Osgood is a passive, persistent, stateless event repository.  The current docs say <em>queue</em> rather than repository but we&#8217;ve decided it&#8217;s a bit of a misnomer.  A primer on the aforementioned explanation:</p>
<p>* Passive: Osgood doesn&#8217;t seek out your events, it only waits for notification and query<br />
* Stateless: Querying an event does not change it<br />
* Repository: Once you&#8217;ve inserted an event it stays there forever</p>
<p>So what&#8217;s that mean?  Osgood (::Server) is a system wherein you record the fact that something happened.  A client library is provided that allows you to do just that (::Client).  You can also query the server to ask it what has happened and it will inform you.  I believe an example is in order.</p>
<p>Magazines.com&#8217;s backend is basically a big order pipeline after the order is taken.  We are phasing out an AS/400 which is currently handling fulfillment of orders.  If a customer calls us and wants to cancel a magazine, our our order entry system cancels the order and then needs to notify the AS/400.  We have an audit table for order line items, so we would query that table for fresh cancels and send them to the 400 to finish the process.</p>
<p>All was well!  Then our Marketing team approached us with a good idea: Send customers who&#8217;ve canceled an email enticing them back!  It was a great idea until we released that we basically had one shot in our aforementioned setup to send a cancel, and we were using it.  There was no way to keep up with the status.  Had we sent it to the 400?  What about to our email service provider?  Were there other things we might do in the future?  Osgood was born.</p>
<p>Osgood is based around Events.  You use ::Client to send an event to the Osgood server, like so:</p>
<p><code lang="perl"><br />
my $event = new Osgood::Event(<br />
	object => 'Moose',<br />
	action => 'farted',<br />
	date_occurred => DateTime->now(),<br />
	params => {<br />
		name => 'Hector'<br />
	}<br />
);<br />
</code></p>
<p>Events are composed of an object, an action and a time.  These fields are all stored as <code>VARCHAR(64)</code>s, so you can put anything you like up to that size.</p>
<p>The optional <code>params</code> accepts a hashref of name value pairs.  This allows storage of information that doesn&#8217;t fit Osgood&#8217;s Object/Event setup, but that you might need when using the event.  A good example would be the primary key of the specific Moose that farted.  Note that you can also use <code>get\_param</code> and <code>set\_param</code> on an Event object.</p>
<p><code lang="perl"><br />
my $list = new Osgood::EventList(events => [ $event ])<br />
my $client = new Osgood::Client(<br />
	url => 'http://localhost',<br />
	list => $list<br />
);<br />
my $retval = $client->send();<br />
if($list->size() == $retval) {<br />
	print "Success :)\n";<br />
} else {<br />
	print "Failure :(\n";<br />
}<br />
</code></p>
<p>You can put as many events into an EventList as you like.  Then you create a Client and send it!  Above we check that <code>send</code> returned a number that matches the events we sent.</p>
<p>That&#8217;s all well and good, but how do you <strong>use</strong> what you&#8217;ve stored?  The client also works the other way around:</p>
<p><code lang="perl"><br />
my $retval = $client->query({<br />
     object => 'Moose',<br />
     action => 'farted',<br />
});</p>
<p>if($retval) {<br />
	# Gets an EventList<br />
	my $list = $client->list();<br />
	my $iterator = $list->iterator();<br />
	while($iterator->has_next()) {<br />
		my $event = $iterator->next();<br />
		print $event->get_param('name')." farted at ".$event->date_occurred()."\n";<br />
	}<br />
} else {<br />
	print "Oh noes!\n";<br />
}<br />
</code></p>
<p>We asked Osgood for all the Moose/farted events and we got them back.  One note of interest is that Events are assigned an ID when they are stored, and that ID is present when you get them in a query.  This will come in useful later.</p>
<p>The <code>query</code> method supports many other options as of this writing:</p>
<p>* date_after: date after the specified one<br />
* date_before: date before the specified one<br />
* id: all events with an id greater than the one specified<br />
* limit: only return the specified number of events</p>
<p>So back to our original problem.  Rather than make our internal cancel process complex, we simply create a row in a queue table which is emptied frequently and sent to Osgood.  Our backend processing jobs then query Osgood using the <code>id</code> parameter to query to find every event that was created <em>since the last one it processed</em>.  Now we can create an unlimited number of backend jobs that work from the same event.  Our email sending and publisher notification of cancels happen independently.</p>
<p>This work was inspired by past work with Publisher/Subscriber systems and message queues like the venerable JMS.  It bears very little resemblance to those ideas, but one might be able to squint a bit and see the similarity.</p>
<p>Osgood::Server is a Catalyst application using the XML::REST plugin and ::Client is Moose based with some help from MooseX::Iterator and some XML::XPath and XML::DOM magic for serializing and deserializing the eventlist.</p>
<p>If you have any questions, feel free to drop me an email or hit me up on irc.perl.org as <code>gphat</code>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.onemogin.com/blog/579-announcing-osgood-an-event-repository/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Hanging Antlers On Your ResultSets</title>
		<link>http://www.onemogin.com/blog/578-hanging-antlers-on-your-resultsets</link>
		<comments>http://www.onemogin.com/blog/578-hanging-antlers-on-your-resultsets#comments</comments>
		<pubDate>Fri, 29 Feb 2008 00:50:59 +0000</pubDate>
		<dc:creator>gphat</dc:creator>
				<category><![CDATA[Catalyst]]></category>
		<category><![CDATA[Code]]></category>
		<category><![CDATA[Perl]]></category>

		<guid isPermaLink="false">http://www.onemogin.com/blog/578-hanging-antlers-on-your-resultsets.html</guid>
		<description><![CDATA[At some point in the not too distant future, the intarweb&#8217;s magazine consumers will be perusing a new magazines.com.  I&#8217;ve got the responsibility of building it.  One of the requirements is to allow our Merchandising and Marketing folk to get their jobs done without too much fuss.  The system they use will [...]]]></description>
			<content:encoded><![CDATA[<p>At some point in the not too distant future, the intarweb&#8217;s magazine consumers will be perusing a new <a href="http://www.magazines.com">magazines.com</a>.  I&#8217;ve got the responsibility of building it.  One of the requirements is to allow our Merchandising and Marketing folk to get their jobs done without too much fuss.  The system they use will consume sets of products.  They might want to build a set of magazines in a certain category, under a certain price.  What kind of tool am I talking about?</p>
<p>A Query Builder.</p>
<p>I can hear your eyes rolling already.  We&#8217;ve all written them.  But I&#8217;m going to share an extra-cool method for doing so.</p>
<p>Here&#8217;s the list of ingredients you&#8217;ll need.</p>
<p>* Your existing DBIC application.<br />
* Experience with <a href="http://search.cpan.org/~jrobinson/DBIx-Class-0.08009/lib/DBIx/Class/ResultSource.pm#resultset_class">custom resultsets</a>.<br />
* An understanding of <a href="http://www.onemogin.com/blog/528-chained-searches-the-beauty-of-dbixclass-and-catalyst.html">chained resultset usage</a>.<br />
* <a href="http://search.cpan.org/perldoc?Moose">Moose</a><br />
* <a href="http://search.cpan.org/perldoc?MooseX::Method">MooseX::Method</a></p>
<p>Now that you&#8217;ve collected your ingredients, let&#8217;s prepare them.</p>
<p>First, note that we aren&#8217;t allowing our end users to build *literal queries* in this recipe.  We are going to allow them to chain *calls to our resultset*.  This is a much better option, in my opinion.  A lot of the complexity can be removed by simplifying some heinous or dangerous SQL into a simple resultset method.  With the help of Moose we will create a custom resultset that allows us to introspect the methods available for building and show them to the user automatically.</p>
<p>Now, we&#8217;ll be working on a Product example.  Our end user needs to build a query that finds all the products in a price range, of a certain type and in a certain category.</p>
<p>Since you&#8217;re already versed in custom resultsets I&#8217;ll just show you the finished product:</p>
<p><code lang="perl"><br />
package Our::ResultSet;<br />
use Moose;<br />
use MooseX::Method;<br />
use MooseX::Util::TypeConstraints;</p>
<p>extends 'DBIx::Class::ResultSet';</p>
<p>subtype 'Currency'<br />
	=> as 'Object'<br />
	=> where { $_->isa('Math::Currency') };</p>
<p>coerce 'Currency'<br />
	=> from 'Num'<br />
		=> via { Math::Currency->new($_) };</p>
<p>method price => named (<br />
	operator => { isa => 'Comparator', required => 1 },<br />
	amount	=> { isa => 'Currency', required => 1, coerce => 1 }<br />
) => sub {<br />
	my ($self, $args) = @_;</p>
<p>	if($args->{'operator'} eq '=') {<br />
		return $self->search({ price => $args->{'amount'}->as_float() });<br />
	}</p>
<p>	return $self->search({<br />
		price => {<br />
			$args->{'operator'} => $args->{'amount'}->as_float()<br />
		}<br />
	});<br />
};<br />
</code></p>
<p>That&#8217;s a lot of code, but the concept is very simple:  Create your resultset&#8217;s methods with MooseX::Method and then you can do the following magic:</p>
<p><code lang="perl"><br />
my $rs = $schema->resultset('Product');<br />
my $map = $rs->meta->get_method_map();<br />
foreach my $method (keys(%{ $map })) {<br />
	# See MooseX::Method docs for what to do with this.<br />
	my $signature = $method->signature();<br />
	# Profit!<br />
}<br />
</code></p>
<p>Having the method&#8217;s &#8217;signature&#8217; allows you to get a list of the parameters that the method expects, as well as the types and &#8216;required&#8217; status.  That sounds like the recipe for some go-getting developer to construct a query building tool!</p>
<p><strong>One warning.</strong>  MooseX::Method currently lacks a permanent API for acquiring this information.  The current API is to call <code>export</code> on the signature.  You can <code>Dumper</code> the resulting hashref and see pretty easily how to get what you need.  Keep an eye on The CPAN or in irc.perl.org&#8217;s #moose for updates.</p>
<p>So to use this recipe, you&#8217;ll have to construct your own mechanism for taking the above information and generating a UI for your application.  I got my Catalyst based query-builder working this afternoon.</p>
<p>If you have any questions feel free to drop into irc.perl.org and shoot a message to <code>gphat</code>.  You can find me in <code>#moose</code>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.onemogin.com/blog/578-hanging-antlers-on-your-resultsets/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Ayalike: Content Management using Catalyst</title>
		<link>http://www.onemogin.com/blog/574-ayalike-content-management-using-catalyst</link>
		<comments>http://www.onemogin.com/blog/574-ayalike-content-management-using-catalyst#comments</comments>
		<pubDate>Sun, 03 Feb 2008 07:49:21 +0000</pubDate>
		<dc:creator>gphat</dc:creator>
				<category><![CDATA[Catalyst]]></category>
		<category><![CDATA[Code]]></category>
		<category><![CDATA[General]]></category>
		<category><![CDATA[Languages]]></category>
		<category><![CDATA[Perl]]></category>
		<category><![CDATA[Useless Information]]></category>
		<category><![CDATA[Work]]></category>

		<guid isPermaLink="false">http://www.onemogin.com/blog/574-ayalike-content-management-using-catalyst.html</guid>
		<description><![CDATA[UPDATE: The demo and trac links are down atm, as Ayalike is being moved to new hosting.
I&#8217;ve been hacking away for the last week or so on a content management system (henceforth CMS).  We are going to need a CMS for some future $work projects and I&#8217;m generally unhappy with all that I&#8217;ve reviewed. [...]]]></description>
			<content:encoded><![CDATA[<p>UPDATE: The demo and trac links are down atm, as Ayalike is being moved to new hosting.</p>
<p>I&#8217;ve been hacking away for the last week or so on a content management system (henceforth CMS).  We are going to need a CMS for some future $work projects and I&#8217;m generally unhappy with all that I&#8217;ve reviewed.  So many of the existing &#8217;solutions&#8217; seem to be more in the business of providing you with a &#8216;platform&#8217;.  Most of the folks I know build platforms for a living, we need only find a way to *manage the content*.</p>
<p>So with that in mind, Ayalike (pronounced like &#8216;a uh like&#8217;) aims to provide the following features:</p>
<p>* Multisite, multiuser, multirole<br />
* Output agnostic<br />
* Versioning<br />
* Pluggable publishing<br />
* Output processing</p>
<p>Three of those features are complete.  Publishing works, but is currently not pluggable.  Output processing is there as well, but I&#8217;ve yet to hook it into anything but unit tests.</p>
<p>That&#8217;s all kind of abstract, here&#8217;s what I&#8217;ve done in a more concrete form:  This week I modified one of our internal applications to use a custom <a href="http://search.cpan.org/dist/Template-Toolkit/">Template Toolkit</a> provider that communicated with Ayalike and provided &#8216;preview&#8217; functionality on the live site *without changes to the application itself*.  The application functioned normally, rendering compiled templates from the filesystem, unless given a special parameter.  In that case it requested the entry from Ayalike over HTTP using it&#8217;s wiki-esque page viewing feature.  Obviously real apps would protect this feature with logins.</p>
<p>I&#8217;m not quite ready to tout it on the mailing lists or in IRC yet, but I&#8217;m very excited about the project and I hope that it might become the solution for my future work projects.  Regardless, Catalyst needs a CMS.</p>
<p>Are you interested?  Visit the <a href="http://trac.oneforthehustle.com/ayalike">Trac site</a>.  There&#8217;s even a <a href="http://ayalike.oneforthehustle.com">working demo</a>, cleared every half hour.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.onemogin.com/blog/574-ayalike-content-management-using-catalyst/feed</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>DBIx-Class-QueryLog 1.0.0 Released</title>
		<link>http://www.onemogin.com/blog/564-dbix-class-querylog-100-released</link>
		<comments>http://www.onemogin.com/blog/564-dbix-class-querylog-100-released#comments</comments>
		<pubDate>Fri, 31 Aug 2007 01:37:27 +0000</pubDate>
		<dc:creator>gphat</dc:creator>
				<category><![CDATA[Catalyst]]></category>
		<category><![CDATA[Code]]></category>
		<category><![CDATA[Languages]]></category>
		<category><![CDATA[Perl]]></category>
		<category><![CDATA[Work]]></category>

		<guid isPermaLink="false">http://www.onemogin.com/blog/564-dbix-class-querylog-100-released.html</guid>
		<description><![CDATA[I just uploaded the 1.0.0 release of DBIx::Class::QueryLog to the CPAN.
The 1.0.0 label is mostly just a not to it&#8217;s maturity.  I&#8217;ve been using QueryLog extensively at $job &#8212; most recently to tune a multi-million order conversion script &#8212; and a 1.0 is in order.
The only new feature is a refactoring of the &#8216;analysis&#8217; [...]]]></description>
			<content:encoded><![CDATA[<p>I just uploaded the 1.0.0 release of DBIx::Class::QueryLog to the <a href="http://www.cpan.org">CPAN</a>.</p>
<p>The 1.0.0 label is mostly just a not to it&#8217;s maturity.  I&#8217;ve been using QueryLog extensively at $job &#8212; most recently to tune a multi-million order conversion script &#8212; and a 1.0 is in order.</p>
<p>The only new feature is a refactoring of the &#8216;analysis&#8217; code into a seperate object, as well as a new mode that totals up queries, combinining same queries and keeping a count and total time for all executions.</p>
<p>Have fun!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.onemogin.com/blog/564-dbix-class-querylog-100-released/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Adding Action Timings To Your Output</title>
		<link>http://www.onemogin.com/blog/559-adding-action-timings-to-your-output</link>
		<comments>http://www.onemogin.com/blog/559-adding-action-timings-to-your-output#comments</comments>
		<pubDate>Fri, 18 May 2007 13:36:45 +0000</pubDate>
		<dc:creator>gphat</dc:creator>
				<category><![CDATA[Catalyst]]></category>
		<category><![CDATA[Code]]></category>
		<category><![CDATA[Languages]]></category>
		<category><![CDATA[Perl]]></category>

		<guid isPermaLink="false">http://www.onemogin.com/blog/559-adding-action-timings-to-your-output.html</guid>
		<description><![CDATA[UPDATE: Jon Schutz recently posted an update to this idea.  Please use his!
When handing a request Catalyst politely outputs each action executed (in order) along with it&#8217;s timings, like so:

2007/05/17 13:52:18 INFO [Catalyst : 1506] Request took 0.429198s (2.330/s)
.----------------------------------------------------------------+-----------.
&#124; Action               [...]]]></description>
			<content:encoded><![CDATA[<p><b>UPDATE:</b> Jon Schutz recently <a href="http://notes.jschutz.net/17/perl/adding-action-timings-to-your-catalyst-output">posted an update</a> to this idea.  Please use his!</p>
<p>When handing a request Catalyst politely outputs each action executed (in order) along with it&#8217;s timings, like so:</p>
<pre>
2007/05/17 13:52:18 INFO [Catalyst : 1506] Request took 0.429198s (2.330/s)
.----------------------------------------------------------------+-----------.
| Action                                                         | Time      |
+----------------------------------------------------------------+-----------+
| /auto                                                          | 0.102865s |
| /default                                                       | 0.040768s |
|  -> /search/default                                            | 0.028275s |
| /end                                                           | 0.171297s |
|  -> Greenspan::Lockhart::View::TT->process                     | 0.165873s |
'----------------------------------------------------------------+-----------'
</pre>
<p>This information is helpful when trying to trace the flow of execution, find an error or when trying to isolate which action is hindering speedy throughput. But what does one do when multiple people are using a load-balanced app simulataneously?  Tailing error_log on 3 webservers isn&#8217;t as much fun as the kids make it out to be!  My <a href="http://www.onemogin.com/blog/554-profile-your-catalystdbixclass-app-with-querylog.html">work</a> on <a href="http://search.cpan.org/~gphat/DBIx-Class-QueryLog/lib/DBIx/Class/QueryLog.pm">DBIx::Class::QueryLog</a> has me in the mode of providing performance information in the footer of the page.  So I set out to do the same for Catalyst actions.</p>
<p>Turns out this is easier than it sounds.  Catalyst keeps a <a href="http://search.cpan.org/~stevan/Tree-Simple/lib/Tree/Simple.pm">Tree::Simple</a> object in $c-&gt;stats() that details execution.  Each node is a hashref containing (at minimum) &#8216;action&#8217; and &#8216;elapsed&#8217; keys.  The former being the name of the action and the latter being how long it took to execute.  Oddly, that latter value is not a plain number, but a float followed by an &#8217;s&#8217; to denote it is in seconds.</p>
<p>A quick snippet of code placed into the &#8216;end&#8217; of my root controller can digest this tree and produce something useful for my templates:</p>
<p><code lang="perl"><br />
my $tree = $c->stats();</p>
<p>my $dvisit = new Tree::Simple::Visitor();<br />
$tree->accept($dvisit);<br />
$c->stash->{'action_stats'} = $dvisit->getResults();<br />
</code></p>
<p>The value of the &#8216;action_stats&#8217; key is now an array of hashrefs representing each action in the chain in execution order.  A simple FOREACH and we&#8217;ve got ourselves a list of actions with their timings.</p>
<p><img src="http://www.onemogin.com/images/action-timings.png" /></p>
<p>The actions could be arranged in order of time elapsed using Tree::Simple::Vistitor::Sort, but I personally prefer execution order.  YMMV.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.onemogin.com/blog/559-adding-action-timings-to-your-output/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Profile Your Catalyst/DBIC App with QueryLog</title>
		<link>http://www.onemogin.com/blog/554-profile-your-catalystdbixclass-app-with-querylog</link>
		<comments>http://www.onemogin.com/blog/554-profile-your-catalystdbixclass-app-with-querylog#comments</comments>
		<pubDate>Thu, 01 Mar 2007 20:37:01 +0000</pubDate>
		<dc:creator>gphat</dc:creator>
				<category><![CDATA[Catalyst]]></category>
		<category><![CDATA[Code]]></category>
		<category><![CDATA[General]]></category>
		<category><![CDATA[Perl]]></category>
		<category><![CDATA[Work]]></category>

		<guid isPermaLink="false">http://www.onemogin.com/blog/554-profile-your-catalystdbixclass-app-with-querylog.html</guid>
		<description><![CDATA[Months ago I implemented DBIx::Class::Storage::Statistics with the intent of making some sort of profiling tool.  I finally got off my ass and did it.  DBIx::Class::QueryLog should be on CPAN this weekend.
At $work we are replacing a legacy system with one based on Catalyst.  One of the deliverables for this year is a [...]]]></description>
			<content:encoded><![CDATA[<p>Months ago I implemented DBIx::Class::Storage::Statistics with the intent of making some sort of profiling tool.  I finally got off my ass and did it.  DBIx::Class::QueryLog should be on CPAN this weekend.</p>
<p>At $work we are replacing a legacy system with one based on Catalyst.  One of the deliverables for this year is a new order entry application.  Since our customer service folks are used to working in a terminal based system speed is of great concern to us.</p>
<p>So I installed DBIx::Class::QueryLog as the debugobj as described in it&#8217;s documentation, dropped it in the stash and added some code to our wrapper.tmpl:</p>
<p><code lang="html4strict"><br />
      [% IF querylog %]</p>
<div class="featurebox">
<h3>Query Log Report</h3>
<p>        [% SET total = querylog.time_elapsed | format('%0.6f') %]</p>
<div>Total SQL Time: [% total | format('%0.6f') %] seconds</div>
<p>        [% SET qcount = querylog.count %]</p>
<div>Total Queries: [% qcount %]</div>
<p>        [% IF qcount %]</p>
<div>Avg Statement Time: [% (querylog.time_elapsed / qcount) | format('%0.6f') %] seconds.</div>
<div>
<table class="table1">
<thead>
<tr>
<th colspan="3">5 Slowest Queries</th>
</tr>
</thead>
<tbody>
<tr>
<th>Time</th>
<th>%</th>
<th>SQL</th>
</tr>
<p>           [% SET i = 0 %]<br />
           [% FOREACH q = querylog.get_sorted_queries %]</p>
<tr class="[% IF loop.count % 2 %]odd[% END %]">
<th class="sub">[% q.time_elapsed | format('%0.6f') %]</p>
<td>[% ((q.time_elapsed / total ) * 100 ) | format('%i') %]%</td>
<td>[% q.sql %]</td>
</th>
</tr>
<p>           [% IF i == 5 %]<br />
            [% LAST %]<br />
           [% END %]<br />
           [% SET i = i + 1 %]<br />
           [% END %]<br />
          </tbody>
</table></div>
<p>        [% END %]
      </p></div>
<p>      [% END %]<br />
</code></p>
<p>The first run yielded this:</p>
<p><img src="http://www.onemogin.com/blog/stuff/querylog1.png"/></p>
<p>Well.  That select from users could use an index on username, eh?</p>
<p><img src="http://www.onemogin.com/blog/stuff/querylog2.png"/></p>
<p>Weee!  That one disappeared.  What are all these role selections?  We use Catalyst::Plugin::Authorization::Roles but this looks fishy.  We might could use an index on the role name but there are only 6 rows in that table.  A bit more investigation finds a loop in our Root controller that iterates over a set of roles calling check_user_roles() to try and find out where we should redirect the user.  So lets swap that out for creating an array of roles and using grep&#8230;</p>
<p><img src="http://www.onemogin.com/blog/stuff/querylog3.png"/></p>
<p>Kick ass!  We are down to two measly queries.  We reduced the number of queries by about 75% and decreased the time spent executing SQL by about 75% as well.  These queries were being executed on <strong>every</strong> page load.</p>
<p><strong>UPDATE:</strong>Yeah, the average statement time was broken during that.  Oops.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.onemogin.com/blog/554-profile-your-catalystdbixclass-app-with-querylog/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>
