<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title type="text">Blog entries tagged screencast :: mwop.net</title>
  <updated>2012-09-20T17:30:00-05:00</updated>
  <generator uri="https://getlaminas.org" version="2">Laminas_Feed_Writer</generator>
  <link rel="alternate" type="text/html" href="https://mwop.net/blog/tag/screencast"/>
  <link rel="self" type="application/atom+xml" href="https://mwop.net/blog/tag/screencast/atom.xml"/>
  <id>https://mwop.net/blog/tag/screencast</id>
  <entry xmlns:xhtml="http://www.w3.org/1999/xhtml">
    <title type="html"><![CDATA[Screencasting on Linux]]></title>
    <published>2012-09-20T17:30:00-05:00</published>
    <updated>2012-09-20T17:30:00-05:00</updated>
    <link rel="alternate" type="text/html" href="https://mwop.net/blog/2012-09-20-screencasting-on-linux.html"/>
    <id>https://mwop.net/blog/2012-09-20-screencasting-on-linux.html</id>
    <author>
      <name>Matthew Weier O'Phinney</name>
      <email>contact@mwop.net</email>
      <uri>https://mwop.net</uri>
    </author>
    <content xmlns:xhtml="http://www.w3.org/1999/xhtml" type="xhtml">
      <xhtml:div xmlns:xhtml="http://www.w3.org/1999/xhtml"><xhtml:p>I've been wanting to do screencasts on Linux for some time now,
and my big stumbling block has been determining what tools to
use.</xhtml:p>
<xhtml:p>The <xhtml:strong>tl;dr</xhtml:strong>:</xhtml:p>
<xhtml:ul>
<xhtml:li>Use <xhtml:code>recordMyDesktop</xhtml:code> to record video clips, but
afterwards, re-encode them to AVI (<xhtml:a href="#script">see the script
I used</xhtml:a>)</xhtml:li>
<xhtml:li>Record audio to WAV, or convert compressed audio to WAV format
afterwards.</xhtml:li>
<xhtml:li>Use OpenShot to stitch clips together and layer audio and video
tracks.</xhtml:li>
<xhtml:li>Remember to reset the video length if you change the playback
rate.</xhtml:li>
<xhtml:li>Export to a Web + Vimeo profile for best results.</xhtml:li>
</xhtml:ul>
<xhtml:h2>Stumbling Blocks</xhtml:h2>
<xhtml:p><xhtml:code>recordMyDesktop</xhtml:code> is a fairly simple tool, and allows
you to record actions you're taking, and simultaneously capture
audio. However, it creates an ".ogv" (Ogg Vorbis video file) —
which is basically useless for anybody not on Linux or FreeBSD.
Additionally, I often like to record in segments; this makes it
less likely that I'll make mistakes, and, if I do, I only need to
record a small segment again, not the entire thing.
<xhtml:code>recordMyDesktop</xhtml:code> is only for creating screencasts, not
merging them.</xhtml:p>
<xhtml:p>So, <xhtml:code>recordMyDesktop</xhtml:code> went into my toolbox for the
purpose of recording the video portion of my screencasts.</xhtml:p>
<xhtml:p>Which brings me to the next point: I also prefer to record the
audio separately from the screencast portion itself; this way I
don't get typing sounds in the recording, and I'm less likely to
lose my train of thought as I'm speaking. To this end, I ended up
using quite simply the "Sound Recorder" utility
(<xhtml:code>gnome-sound-recorder</xhtml:code>). It's not great, but with a
reasonable microphone, it gets the job done. I chose to record the
audio as MP3 files.</xhtml:p>
<xhtml:p>However, this means that I now have video and audio tracks. So
my toolbox needed a utility for overlaying tracks and laying them
out on a timeline independently.</xhtml:p>
<xhtml:p>I looked at a few different free tools for Linux, including
<xhtml:code>Avidemux</xhtml:code>, <xhtml:code>Cinelerra</xhtml:code>, and
<xhtml:code>PiTiVi</xhtml:code>. <xhtml:code>Avidemux</xhtml:code> was not featurful
enough, <xhtml:code>Cinelerra</xhtml:code> was too difficult to learn (it's
more of an advanced user's tool), and <xhtml:code>PiTiVi</xhtml:code> kept
crashing on me. So, I used the lazyweb, and tweeted a question
asking what others were using — and the unanimous response was
<xhtml:code>OpenShot</xhtml:code> (<xhtml:a href="http://www.openshotvideo.com/">http://www.openshotvideo.com/</xhtml:a>).</xhtml:p>
<xhtml:p><xhtml:code>OpenShot</xhtml:code> hit the sweet spot for me -- it was easy
to pick up, and didn't crash. However, I discovered problems when I
exported my project to a video file. My video, regardless of
whether or not I changed the playback rate, always played at about
2X normal speed. The audio always truncated 1 to 2 seconds before
completion.</xhtml:p>
<xhtml:p>In doing some research, I discovered:</xhtml:p>
<xhtml:ul>
<xhtml:li>There are known issues with Ogg Vorbis video files. Evidently,
the compression creates issues when re-encoding the video to
another format.</xhtml:li>
<xhtml:li>Similarly, compressed audio can lead to issues such as
truncation.</xhtml:li>
</xhtml:ul>
<xhtml:p>Since <xhtml:code>recordMyDesktop</xhtml:code> doesn't allow you to select
an alternate video codec, I had to use <xhtml:code>mencoder</xhtml:code> to
transcode it to another format. I chose AVI (Audio Video
Interleave, a video container format developed by Microsoft), as I
knew it had widespread support, using an mpeg4 codec (also widely
supported). I used the following script, found at <xhtml:a href="http://askubuntu.com/questions/17309/video-converter-ogv-to-avi-or-another-more-common-format">
http://askubuntu.com/questions/17309/video-converter-ogv-to-avi-or-another-more-common-format</xhtml:a>,
in order to encode my files:</xhtml:p>
<xhtml:pre><xhtml:code class="language-bash hljs bash" data-lang="bash"><xhtml:span class="hljs-keyword">for</xhtml:span> f <xhtml:span class="hljs-keyword">in</xhtml:span> *.ogv;<xhtml:span class="hljs-keyword">do</xhtml:span>
    newFile=<xhtml:span class="hljs-variable">${f%.*}</xhtml:span>
    mencoder <xhtml:span class="hljs-string">"<xhtml:span class="hljs-variable">$f</xhtml:span>"</xhtml:span> -o <xhtml:span class="hljs-string">"<xhtml:span class="hljs-variable">$newFile</xhtml:span>.avi"</xhtml:span> -oac mp3lame -lameopts fast:preset=standard -ovc lavc -lavcopts vcodec=mpeg4:vbitrate=4000
<xhtml:span class="hljs-keyword">done</xhtml:span>
</xhtml:code></xhtml:pre>
<xhtml:p>That solved the video issue, but I still had to solve the audio
issues. I quickly re-recorded one audio segment in Sound Recorder,
and told it to use the "Voice,Lossless (.wav type)". When I used
this version of the audio, I had no issues, other than the audio
length being mis-reported within <xhtml:code>OpenShot</xhtml:code>. Instead of
re-recording all segments, I installed the "Sound Converter"
utility (<xhtml:code>sudo aptitude install soundconverter</xhtml:code>), and
used that to convert all my MP3 files to WAV. Interestingly,
<xhtml:code>OpenShot</xhtml:code> reported the audio lengths correctly this
time; go figure.</xhtml:p>
<xhtml:p>Once that was done, I was able to start stitching everything
together. A few notes, in the hopes others learn from my
mistakes:</xhtml:p>
<xhtml:ul>
<xhtml:li>Several times, I wanted my video to playback slower. This is
very easy to do: right click on the clip, select "Properties", and
select the "Speed" tab, and adjust as necessary. However, that's
not all you need to do; you need to also re-adjust the
<xhtml:em>length</xhtml:em> of the clip. Simply take the existing length, and
divide it by the rate of play. As an example, if the length is 44
seconds, and you specify a 1/2 rate (0.5), you'd do 44 / 0.5 = 88,
and set the length of the clip to 88s.</xhtml:li>
<xhtml:li>If you find that <xhtml:code>OpenShot</xhtml:code> is reporting your audio
clip lengths incorrectly, use another tool to find the accurate
length, and then set the length to that. I typically rounded up to
the next second, as most tools were giving the floor value from
rounding.</xhtml:li>
<xhtml:li>I chose to export using the Web + Vimeo HD profile. This worked
perfectly for me. It created an mpeg4 file that I could preview in
a browser, and then upload without issues. Your mileage may
vary.</xhtml:li>
</xhtml:ul>
<xhtml:p>Hopefully, this will serve as a reasonable guide for others
foraying into screencasts on Linux!</xhtml:p>
<xhtml:div class="h-entry"><xhtml:img class="u-photo photo" width="50" src="https://avatars0.githubusercontent.com/u/25943?v=3&amp;u=79dd2ea1d4d8855944715d09ee4c86215027fa80&amp;s=140" alt="matthew"/> <xhtml:a class="u-url u-uid p-name" href="https://mwop.net/blog/2012-09-20-screencasting-on-linux.html">Screencasting
on Linux</xhtml:a> was originally published <xhtml:time class="dt-published" datetime="2012-09-20T17:30:00-05:00">20 September 2012</xhtml:time> on
<xhtml:a href="https://mwop.net">https://mwop.net</xhtml:a> by <xhtml:a rel="author" class="p-author" href="https://mwop.net">Matthew Weier
O'Phinney</xhtml:a>.</xhtml:div>
</xhtml:div>
    </content>
  </entry>
  <entry xmlns:xhtml="http://www.w3.org/1999/xhtml">
    <title type="html"><![CDATA[ZF2 Modules Quickstart (Screencast)]]></title>
    <published>2012-09-19T13:10:00-05:00</published>
    <updated>2012-09-19T13:10:00-05:00</updated>
    <link rel="alternate" type="text/html" href="https://mwop.net/blog/2012-09-19-zf2-module-screencast.html"/>
    <id>https://mwop.net/blog/2012-09-19-zf2-module-screencast.html</id>
    <author>
      <name>Matthew Weier O'Phinney</name>
      <email>contact@mwop.net</email>
      <uri>https://mwop.net</uri>
    </author>
    <content xmlns:xhtml="http://www.w3.org/1999/xhtml" type="xhtml">
      <xhtml:div xmlns:xhtml="http://www.w3.org/1999/xhtml"><xhtml:p>One of the exciting features of the newly released Zend
Framework 2 is the new module system.</xhtml:p>
<xhtml:p>While ZF1 had modules, they were difficult to manage. All
resources for all modules were initialized on each request, and
bootstrapping modules was an onerous task. Due to the difficulties,
modules were never truly "plug-and-play", and thus no ecosystem
ever evolved for sharing modules.</xhtml:p>
<xhtml:p>In Zend Framework 2, we've architected the MVC from the ground
up to make modular applications as easy as possible. Within ZF2,
the MVC simply cares about events and services — and controllers
are simply one kind of service. As such, modules are primarily
about telling the MVC about services and wiring event
listeners.</xhtml:p>
<xhtml:p>To give you an example, in this tutorial, I'll show you how to
install the Zend Framework 2 skeleton application, and we'll then
install a module and see how easy it is to add it to the
application and then configure it.</xhtml:p>
<xhtml:p>To keep things simple, I'm using a unix-like environment. As
such, if you are on Windows, you may not have the same command-line
tools available. If you are in such a situation, perhaps try this
inside a Linux virtual machine.</xhtml:p>
<xhtml:p><xhtml:a href="https://vimeo.com/49775540">Zend Framework 2 Module
Quickstart</xhtml:a></xhtml:p>
<xhtml:p>Let's start by creating a new project. We'll execute a few
commands to download a skeleton application archive and extract
it.</xhtml:p>
<xhtml:pre><xhtml:code class="language-bash hljs bash" data-lang="bash">$ mkdir newproject
$ <xhtml:span class="hljs-built_in">cd</xhtml:span> newproject
$ wget https://github.com/zendframework/ZendSkeletonApplication/tarball/master \
&gt; -O ZendSkeletonApplication.tgz
$ tar xzf ZendSkeletonApplication.tgz --strip-components=1
</xhtml:code></xhtml:pre>
<xhtml:p>The Zend Framework skeleton application can be downloaded
directly off of <xhtml:a href="https://github.com">GitHub</xhtml:a>. I'm
showing using the download from master, but you can also download a
tarball or zipball for individual tags as well. Because the
download URL does not include an extension, I use the
<xhtml:code>-O</xhtml:code> switch to tell <xhtml:code>wget</xhtml:code> what filename to
save to.</xhtml:p>
<xhtml:p><xhtml:code>tar</xhtml:code> has a nice option,
<xhtml:code>--strip-components</xhtml:code>, which allows you to tell it to
descend a certain number of levels deep into the archive when
deflating. Since I know the tarball has a top-level directory named
after the repository and a sha1, I'm simply telling
<xhtml:code>tar</xhtml:code> to skip that and give me the contents of its child
directory.</xhtml:p>
<xhtml:p>At this point you have the skeleton application, but it has no
dependencies — not even Zend Framework itself! Let's rectify that
situation. We'll use the dependency management tool <xhtml:a href="https://getcomposer.org/">Composer</xhtml:a> to do this. We include the
Composer phar file within the skeleton application to make this
fairly easy. Simply execute the following:</xhtml:p>
<xhtml:pre><xhtml:code class="language-bash hljs bash" data-lang="bash">$ php composer.phar install
</xhtml:code></xhtml:pre>
<xhtml:p>You may get a notice indicating that the composer version is
older, and to run <xhtml:code>self-update</xhtml:code>; you can ignore that for
now.</xhtml:p>
<xhtml:p>If all goes well, you should now have Zend Framework installed.
Let's test it out. I'm going to use the built-in web server in PHP
5.4 to demonstrate.</xhtml:p>
<xhtml:pre><xhtml:code class="language-bash hljs bash" data-lang="bash">$ <xhtml:span class="hljs-built_in">cd</xhtml:span> public
$ php -S localhost:8080
</xhtml:code></xhtml:pre>
<xhtml:p>If I browse to <xhtml:code>http://localhost:8080</xhtml:code> I should now
see the landing page for the skeleton application.</xhtml:p>
<xhtml:p><xhtml:img src="/images/screencasts/2012-09-19-zf2-module-screencast-01-zsa.png" alt=""/></xhtml:p>
<xhtml:p>Let's add a module to the application. Many sites require a
contact form. I've written one as a module some time ago, and
called it <xhtml:a href="https://github.com/weierophinney/PhlyContact">PhlyContact</xhtml:a>. To
install it, I'll edit my project's <xhtml:code>composer.json</xhtml:code> and
tell it about that dependency:</xhtml:p>
<xhtml:pre><xhtml:code class="language-javascript hljs javascript" data-lang="javascript">{
    <xhtml:span class="hljs-string">"require"</xhtml:span>: {
        <xhtml:span class="hljs-string">"php"</xhtml:span>: <xhtml:span class="hljs-string">"&gt;=5.3.3"</xhtml:span>,
        <xhtml:span class="hljs-string">"zendframework/zendframework"</xhtml:span>: <xhtml:span class="hljs-string">"dev-master"</xhtml:span>,
        <xhtml:span class="hljs-string">"phly/phly-contact"</xhtml:span>: <xhtml:span class="hljs-string">"dev-master"</xhtml:span>
    }
}
</xhtml:code></xhtml:pre>
<xhtml:p>I know the name of the component from <xhtml:a href="http://packagist.org/">http://packagist.org/</xhtml:a>, and I'm telling
Composer that I want to use whatever the latest version is on its
master branch on GitHub. I happen to also know that PhlyContact
requires a dev-master version of Zend Framework, so I'll alter that
dependency for now.</xhtml:p>
<xhtml:p>Now, we need to tell composer to update our dependencies.</xhtml:p>
<xhtml:pre><xhtml:code class="language-bash hljs bash" data-lang="bash">$ php composer.phar update
</xhtml:code></xhtml:pre>
<xhtml:p>After executing the command, we should now see that it has
installed; this may take a little while.</xhtml:p>
<xhtml:p>You need to inform the application about the module. This is so
that we don't have to perform expensive file-system scanning
operations, but also to make it explicit in your code what modules
you're actually using. Enabling a module is usually as easy as
adding an entry to <xhtml:code>config/application.config.php</xhtml:code>:</xhtml:p>
<xhtml:pre><xhtml:code class="language-php hljs php" data-lang="php"><xhtml:span class="hljs-string">'modules'</xhtml:span> =&gt; <xhtml:span class="hljs-keyword">array</xhtml:span>(
    <xhtml:span class="hljs-string">'Application'</xhtml:span>,
    <xhtml:span class="hljs-string">'PhlyContact'</xhtml:span>,
),
</xhtml:code></xhtml:pre>
<xhtml:p>This particular module provides some reasonable defaults. In
particular, it uses a CAPTCHA adapter that doesn't require
additional configuration, and assumes that you will want to use the
default <xhtml:code>Sendmail</xhtml:code> mail transport. As such, we can
simply browse to it now. I happen to know that the module defines a
<xhtml:code>/contact</xhtml:code> end point. Let's fire up our PHP web server
again, and browse to that URL.</xhtml:p>
<xhtml:pre><xhtml:code class="language-bash hljs bash" data-lang="bash">$ <xhtml:span class="hljs-built_in">cd</xhtml:span> public
$ php -S localhost:8080
</xhtml:code></xhtml:pre>
<xhtml:p><xhtml:img src="/images/screencasts/2012-09-19-zf2-module-screencast-02-contact.png" alt=""/></xhtml:p>
<xhtml:p>It just works!</xhtml:p>
<xhtml:p>One philosophy we have for distributable modules in Zend
Framework 2 is that you should not need to touch the code in
modules you install in your application. Instead, you should be
able to configure and override behavior within the application
configuration or in your application's site-specific modules. Let's
alter the contact module to:</xhtml:p>
<xhtml:ul>
<xhtml:li>first, change the URL it responds to, and</xhtml:li>
<xhtml:li>second, use the "file" mail transport.</xhtml:li>
</xhtml:ul>
<xhtml:p>Let's look at the default configuration. I'll browse to
<xhtml:code>vendor/phly/phly-contact/config/</xhtml:code> and look at the
<xhtml:code>module.config.php</xhtml:code> file.</xhtml:p>
<xhtml:pre><xhtml:code class="language-php hljs php" data-lang="php"><xhtml:span class="hljs-keyword">return</xhtml:span> <xhtml:span class="hljs-keyword">array</xhtml:span>(
    <xhtml:span class="hljs-string">'phly_contact'</xhtml:span> =&gt; <xhtml:span class="hljs-keyword">array</xhtml:span>(
        <xhtml:span class="hljs-string">'captcha'</xhtml:span> =&gt; <xhtml:span class="hljs-keyword">array</xhtml:span>(
            <xhtml:span class="hljs-string">'class'</xhtml:span> =&gt; <xhtml:span class="hljs-string">'dumb'</xhtml:span>,
        ),
        <xhtml:span class="hljs-string">'form'</xhtml:span> =&gt; <xhtml:span class="hljs-keyword">array</xhtml:span>(
            <xhtml:span class="hljs-string">'name'</xhtml:span> =&gt; <xhtml:span class="hljs-string">'contact'</xhtml:span>,
        ),
        <xhtml:span class="hljs-string">'mail_transport'</xhtml:span> =&gt; <xhtml:span class="hljs-keyword">array</xhtml:span>(
            <xhtml:span class="hljs-string">'class'</xhtml:span> =&gt; <xhtml:span class="hljs-string">'Zend\Mail\Transport\Sendmail'</xhtml:span>,
            <xhtml:span class="hljs-string">'options'</xhtml:span> =&gt; <xhtml:span class="hljs-keyword">array</xhtml:span>(
            )
        ),
        <xhtml:span class="hljs-string">'message'</xhtml:span> =&gt; <xhtml:span class="hljs-keyword">array</xhtml:span>(
            <xhtml:span class="hljs-comment">/*
            'to' =&gt; array(
                'EMAIL HERE' =&gt; 'NAME HERE',
            ),
            'sender' =&gt; array(
                'address' =&gt; 'EMAIL HERE',
                'name'    =&gt; 'NAME HERE',
            ),
            'from' =&gt; array(
                'EMAIL HERE' =&gt; 'NAME HERE',
            ),
             */</xhtml:span>
        ),
    ),

    <xhtml:span class="hljs-comment">/* ... */</xhtml:span>

    <xhtml:span class="hljs-string">'router'</xhtml:span> =&gt; <xhtml:span class="hljs-keyword">array</xhtml:span>(
        <xhtml:span class="hljs-string">'routes'</xhtml:span> =&gt; <xhtml:span class="hljs-keyword">array</xhtml:span>(
            <xhtml:span class="hljs-string">'contact'</xhtml:span> =&gt; <xhtml:span class="hljs-keyword">array</xhtml:span>(
                <xhtml:span class="hljs-string">'type'</xhtml:span> =&gt; <xhtml:span class="hljs-string">'Literal'</xhtml:span>,
                <xhtml:span class="hljs-string">'options'</xhtml:span> =&gt; <xhtml:span class="hljs-keyword">array</xhtml:span>(
                    <xhtml:span class="hljs-string">'route'</xhtml:span> =&gt; <xhtml:span class="hljs-string">'/contact'</xhtml:span>,
                    <xhtml:span class="hljs-string">'defaults'</xhtml:span> =&gt; <xhtml:span class="hljs-keyword">array</xhtml:span>(
                        <xhtml:span class="hljs-string">'__NAMESPACE__'</xhtml:span> =&gt; <xhtml:span class="hljs-string">'PhlyContact\Controller'</xhtml:span>,
                        <xhtml:span class="hljs-string">'controller'</xhtml:span>    =&gt; <xhtml:span class="hljs-string">'Contact'</xhtml:span>,
                        <xhtml:span class="hljs-string">'action'</xhtml:span>        =&gt; <xhtml:span class="hljs-string">'index'</xhtml:span>,
                    ),
                ),
                <xhtml:span class="hljs-string">'may_terminate'</xhtml:span> =&gt; <xhtml:span class="hljs-keyword">true</xhtml:span>,
                <xhtml:span class="hljs-string">'child_routes'</xhtml:span> =&gt; <xhtml:span class="hljs-keyword">array</xhtml:span>(
                    <xhtml:span class="hljs-string">'process'</xhtml:span> =&gt; <xhtml:span class="hljs-keyword">array</xhtml:span>(
                        <xhtml:span class="hljs-string">'type'</xhtml:span> =&gt; <xhtml:span class="hljs-string">'Literal'</xhtml:span>,
                        <xhtml:span class="hljs-string">'options'</xhtml:span> =&gt; <xhtml:span class="hljs-keyword">array</xhtml:span>(
                            <xhtml:span class="hljs-string">'route'</xhtml:span> =&gt; <xhtml:span class="hljs-string">'/process'</xhtml:span>,
                            <xhtml:span class="hljs-string">'defaults'</xhtml:span> =&gt; <xhtml:span class="hljs-keyword">array</xhtml:span>(
                                <xhtml:span class="hljs-string">'action'</xhtml:span> =&gt; <xhtml:span class="hljs-string">'process'</xhtml:span>,
                            ),
                        ),
                    ),
                    <xhtml:span class="hljs-string">'thank-you'</xhtml:span> =&gt; <xhtml:span class="hljs-keyword">array</xhtml:span>(
                        <xhtml:span class="hljs-string">'type'</xhtml:span> =&gt; <xhtml:span class="hljs-string">'Literal'</xhtml:span>,
                        <xhtml:span class="hljs-string">'options'</xhtml:span> =&gt; <xhtml:span class="hljs-keyword">array</xhtml:span>(
                            <xhtml:span class="hljs-string">'route'</xhtml:span> =&gt; <xhtml:span class="hljs-string">'/thank-you'</xhtml:span>,
                            <xhtml:span class="hljs-string">'defaults'</xhtml:span> =&gt; <xhtml:span class="hljs-keyword">array</xhtml:span>(
                                <xhtml:span class="hljs-string">'action'</xhtml:span> =&gt; <xhtml:span class="hljs-string">'thank-you'</xhtml:span>,
                            ),
                        ),
                    ),
                ),
            ),
        ),
    ),
    <xhtml:span class="hljs-comment">/* ... */</xhtml:span>
);
</xhtml:code></xhtml:pre>
<xhtml:p>Okay, that's interesting. I can define the captcha and options
to use, the name of the contact form, the mail transport I want to
use, and even who the email is sent from and who it goes to. In
addition, it defines some routes.</xhtml:p>
<xhtml:p>I'll create a new file,
<xhtml:code>config/autoload/phly-contact.local.php</xhtml:code>. This is a
local configuration file that will not be checked into my version
control system. Now, let's add some configuration. First, I'll
configure my mail transport.</xhtml:p>
<xhtml:pre><xhtml:code class="language-php hljs php" data-lang="php"><xhtml:span class="hljs-keyword">return</xhtml:span> <xhtml:span class="hljs-keyword">array</xhtml:span>(
    <xhtml:span class="hljs-string">'phly_contact'</xhtml:span> =&gt; <xhtml:span class="hljs-keyword">array</xhtml:span>(
        <xhtml:span class="hljs-string">'mail_transport'</xhtml:span> =&gt; <xhtml:span class="hljs-keyword">array</xhtml:span>(
            <xhtml:span class="hljs-string">'class'</xhtml:span>   =&gt; <xhtml:span class="hljs-string">'Zend\Mail\Transport\File'</xhtml:span>,
            <xhtml:span class="hljs-string">'options'</xhtml:span> =&gt; <xhtml:span class="hljs-keyword">array</xhtml:span>(
                <xhtml:span class="hljs-string">'path'</xhtml:span> =&gt; <xhtml:span class="hljs-string">'data/mail/'</xhtml:span>,
            ),
        ),
    ),
);
</xhtml:code></xhtml:pre>
<xhtml:p>I'm telling the module to use the <xhtml:code>File</xhtml:code> mail
transport, and telling the transport where I want messages written.
By default, Zend Framework calls <xhtml:code>chdir()</xhtml:code> to change
directory to the project root, so I can reference a directory
relative to that. I'm simply going to write to a
<xhtml:code>data/mail/</xhtml:code> directory. Let's create that, and make it
world-writable for now to ensure the web server can write to it.
(In production, you'd only want it writable by the web server
user.)</xhtml:p>
<xhtml:pre><xhtml:code class="language-bash hljs bash" data-lang="bash">$ mkdir -p data/mail
$ chmod a+rwX data/mail
</xhtml:code></xhtml:pre>
<xhtml:p>Now, let's change the base URL the contact form responds to; I
want it to respond to <xhtml:code>/contact-us</xhtml:code>. Another principle
of re-usable modules in ZF2 is that we recommend creating tree
routes for each module, with the root of the tree being a literal
route. This makes it easy to alter the base for routing, without
needing to redefine all the routes in the module.</xhtml:p>
<xhtml:p>I'll add the following to my local configuration, then. I'll
simply override the parent route for my module, named "contact",
and point it at a different URL.</xhtml:p>
<xhtml:pre><xhtml:code class="language-php hljs php" data-lang="php">    <xhtml:span class="hljs-string">'router'</xhtml:span> =&gt; <xhtml:span class="hljs-keyword">array</xhtml:span>(
        <xhtml:span class="hljs-string">'routes'</xhtml:span> =&gt; <xhtml:span class="hljs-keyword">array</xhtml:span>(
            <xhtml:span class="hljs-string">'contact'</xhtml:span> =&gt; <xhtml:span class="hljs-keyword">array</xhtml:span>(
                <xhtml:span class="hljs-string">'options'</xhtml:span> =&gt; <xhtml:span class="hljs-keyword">array</xhtml:span>(
                    <xhtml:span class="hljs-string">'route'</xhtml:span> =&gt; <xhtml:span class="hljs-string">'/contact-us'</xhtml:span>,
                ),
            ),
        ),
    ),
</xhtml:code></xhtml:pre>
<xhtml:p>Let's see if all this worked! Once again, I'll fire up PHP's
built-in web server.</xhtml:p>
<xhtml:pre><xhtml:code class="language-bash hljs bash" data-lang="bash">$ <xhtml:span class="hljs-built_in">cd</xhtml:span> public
$ php -S localhost:8080
</xhtml:code></xhtml:pre>
<xhtml:p>Now, let's browse to
<xhtml:code>http://localhost:8080/contact-us</xhtml:code> — looks good! Just as
an experiment, let's try the previously configured URL,
<xhtml:code>http://localhost:8080/contact</xhtml:code>. We get a 404 now!</xhtml:p>
<xhtml:p><xhtml:img src="/images/screencasts/2012-09-19-zf2-module-screencast-03-config.png" alt=""/> <xhtml:img src="/images/screencasts/2012-09-19-zf2-module-screencast-04-404.png" alt=""/></xhtml:p>
<xhtml:p>Now, let's submit the form. I'll fill in some information; it's
asking for my email address, a subject line, and a message, as well
as for me to solve a simple CAPTCHA. Once I've done all that, I can
send it.</xhtml:p>
<xhtml:p>If all is well, we should now have a mail file in our data
directory. Let's check.</xhtml:p>
<xhtml:pre><xhtml:code class="language-bash hljs bash" data-lang="bash">$ ls -l data/mail/
</xhtml:code></xhtml:pre>
<xhtml:p>And now let's look at it.</xhtml:p>
<xhtml:pre><xhtml:code class="language-bash hljs bash" data-lang="bash">$ cat data/mail/ZendMail_1347989389_1009740165.tmp
Date: Tue, 18 Sep 2012 12:29:49 -0500
From: me@mwop.net
Reply-To: me@mwop.net
Subject: [Contact Form] Suspense!

Suspenseful, isn<xhtml:span class="hljs-string">'t it?
</xhtml:span></xhtml:code></xhtml:pre>
<xhtml:p>Looks good!</xhtml:p>
<xhtml:p>Zend Framework 2 provides a wonderful modular architecture that
will enable an ecosystem of 3rd party modules that should save you
time and energy when developing your applications. I've
demonstrated a simple one, a contact form, but many, many more
already exist, and with a stable release now available, you should
see that number grow. This is truly a wonderful step forward for
developers, and I hope you find it as exciting as I do.</xhtml:p>
<xhtml:div class="h-entry"><xhtml:img class="u-photo photo" width="50" src="https://avatars0.githubusercontent.com/u/25943?v=3&amp;u=79dd2ea1d4d8855944715d09ee4c86215027fa80&amp;s=140" alt="matthew"/> <xhtml:a class="u-url u-uid p-name" href="https://mwop.net/blog/2012-09-19-zf2-module-screencast.html">ZF2
Modules Quickstart (Screencast)</xhtml:a> was originally published
<xhtml:time class="dt-published" datetime="2012-09-19T13:10:00-05:00">19
September 2012</xhtml:time> on <xhtml:a href="https://mwop.net">https://mwop.net</xhtml:a> by <xhtml:a rel="author" class="p-author" href="https://mwop.net">Matthew Weier
O'Phinney</xhtml:a>.</xhtml:div>
</xhtml:div>
    </content>
  </entry>
</feed>
