<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[ExpressionEngine Pros - Medium]]></title>
        <description><![CDATA[This is a collection of articles related to the ExpressionEngine CMS owned by EllisLab. The editor and authors in this collection claim no affiliatio with EllisLab and no ownership of the ExpressionEngine trademark. - Medium]]></description>
        <link>https://medium.com/expressionengine-cms?source=rss----8bef2d56cca6---4</link>
        <image>
            <url>https://cdn-images-1.medium.com/proxy/1*TGH72Nnw24QL3iV9IOm4VA.png</url>
            <title>ExpressionEngine Pros - Medium</title>
            <link>https://medium.com/expressionengine-cms?source=rss----8bef2d56cca6---4</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Sat, 14 Nov 2026 06:15:36 GMT</lastBuildDate>
        <atom:link href="https://medium.com/feed/expressionengine-cms" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com/" rel="hub"/>
        <item>
            <title><![CDATA[Reduce the cost of maintaining your ExpressionEngine add-ons with CI_Model]]></title>
            <link>https://medium.com/expressionengine-cms/using-ci-model-to-improve-your-expressionengine-add-ons-8d34d7ac5562?source=rss----8bef2d56cca6---4</link>
            <guid isPermaLink="false">https://medium.com/p/8d34d7ac5562</guid>
            <dc:creator><![CDATA[Patrick Pohler]]></dc:creator>
            <pubDate>Sun, 03 Aug 2014 21:16:41 GMT</pubDate>
            <atom:updated>2014-09-04T02:45:41.311Z</atom:updated>
            <content:encoded><![CDATA[<p><a href="http://en.wikipedia.org/wiki/Don&#39;t_repeat_yourself">The concept of DRY</a> (Don’t Repeat Yourself) is a critical skill to master in writing solid, professional, and maintainable code.</p><p>ExpressionEngine is built on top of CodeIgniter, and while the framework is showing it’s age compared to the new hotness that is Laravel, it does have some decent tools for code re-use.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/200/1*jWlmnMF3wKo04ErO1Of68g.jpeg" /><figcaption>Sorry CodeIgniter fans, just having fun. I’ll take CI over whatever the hell is going on with Wordpress.</figcaption></figure><p>One tool is the <a href="https://ellislab.com/codeigniter/user-guide/general/models.html">CodeIgniter Model class</a> (CI_Model), Models are simply classes designed to contain your application data and are responsible for managing data between your application and the underlying database.</p><p>Wait, doesn’t ExpressionEngine’s Database class do the same thing?</p><p>Not quite, the DB class is great for working with the database, however it isn’t a very reusable way to do common tasks of saving and retrieving data for your application.</p><p>Say you have a table for your add-on called <em>exp_posts</em>. To save a new post you’d use the insert command of the Database class:</p><blockquote>$data = array( ‘title’ =&gt; ‘My title’ , ‘name’ =&gt; ‘My Name’ , ‘date’ =&gt; ‘My date’<br>);</blockquote><blockquote>ee()-&gt;db-&gt;insert(‘posts’, $data);</blockquote><p>Seems simple right? Well say you have this code in a few places in your add-on to insert new posts. You also have code to pull the posts from the database. Now you need to add a new column to the posts table and use it in your add-on.</p><p>Uh-oh, you’ll have to now update all of the places were you’re working with data from the posts table. It’s not a big deal for maybe one table, but as your add-on grows in complexity suddenly every change becomes more of a hassle and starts creating a large number of bugs in your code.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/670/1*E5sG51a8LNFzC87eBdxXwQ.png" /><figcaption>It’s cute until they drink all the coffee and don’t make a fresh pot.</figcaption></figure><p>What we need is a way to encapsulate the idea of a Post into a class were we only have one file we have to maintain when we need to make a change.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/ece096507c81756145c1ac90450ea5cb/href">https://medium.com/media/ece096507c81756145c1ac90450ea5cb/href</a></iframe><p>Above is an example of how I structure the model classes in my add-ons. You can see we have the common CRUD (Create, Read, Update, Delete) methods. It’s pretty similar to the CodeIgniter documentation with a few differences:</p><ul><li>A method called <em>_get_table()</em> which returns the table name, this is handy because it allows us to refer to the table name once rather than having to repeat the table name in every db statement. I made this a private method instead of an attribute because if it was a class attribute, CI’s <em>insert</em> and <em>update</em> methods would assume that it was a table field.</li><li>Two methods, <em>_set_model_for_save()</em> and <em>_set_model_for_return()</em> which handles the mapping between the fields in the table and the properties of the class</li></ul><p>You’ll also note that for one of the properties <em>author_secret </em>we’re encrypting and decrypting the data before and after saving in the mapping methods. By using a Model class I’m able to easily enforce the business rule that this field has to be encrypted when saving to the database. If I ever need to adjust or change this rule (or encrypt other fields) it’s as simple as modifying a few lines in this one class.</p><p>Using the model class is pretty straightforward. If you create a subfolder in your add-on folder called <em>models</em> you can use CodeIngiter’s Loader class to instanantiate the model. Here’s an example using my ExpressionEngine module for <a href="http://retsrabbit.com/">Rets Rabbit</a>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/392/1*bYlKVN4qCFU7G4qYI19skQ.png" /></figure><p>If you use the model method of the Loader class, EE will look in your add-on’s <em>models </em>subfolder. Afterwards you can access the model class by using <em>ee()-&gt;Rets_config</em>.</p><p>Saving data using the becomes really simple, here’s an example of how I use the class to save a new configuration.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/969/1*pFXg5wjlRZjSiKMcNQAGGw.png" /></figure><p>Now this is pretty great. But there’s one more bit of refactoring we can do on our model classes to make sure we’re using DRY principles.</p><p>Do you remember the three private methods I used in my Post example class: <em>_get_table</em>, <em>_set_model_for_save</em>, <em>_set_model_for_return</em>? Well it turns out that they are the only methods that change from model to model. This means we’re repeating the exact same methods: <em>get</em>, <em>get_by_site_id</em>, <em>insert</em>, and <em>update</em>, which isn’t very DRY.</p><p>We can fix this by creating an abstract base class and inheriting our model classes off of it. An abstract base class is like a document template, it contains a common set of reusable code that other classes can derive from.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/45346827157a4d5bf4e02c4e6336f49b/href">https://medium.com/media/45346827157a4d5bf4e02c4e6336f49b/href</a></iframe><p>If you mark a class as <em>abstract </em>you are letting PHP know that it shouldn’t instantiated the class directly, it’s only purpose is to be inherited (if you try to use the class directly, PHP will throw an error). If you mark methods as <em>abstract</em>, you’re telling PHP that those methods must be defined in the child classes. The rest of the methods and properties are common to all classes and won’t have to be defined (unless a child class needs to override them).</p><p>Now our Post class looks a lot simpler.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/84da13c523655a5607b9736cdc2495f7/href">https://medium.com/media/84da13c523655a5607b9736cdc2495f7/href</a></iframe><p>Now whenever I need to add a new Model to my add-on, all I have to do is create a model class that inherits from Base_model and then modify the three protected methods to fit the data I’m storing.</p><p>Code re-usability is the mark of a true professional, it’s not sexy, but reliable and maintainable code will help you deal better with support issues help other developers understand and work with your code. As we’ve seen above, CodeIgniter gives us some decent tools to help us encapsulate our data into model classes and keep things DRY.</p><p><em>Patrick is the owner of the development agency </em><a href="http://www.anecka.com/"><em>Anecka</em></a><em>. He also writes articles and guides for freelancers to help improve their development productivity at </em><a href="http://www.patpohler.com/"><em>PatPohler.com</em></a><em>.</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=8d34d7ac5562" width="1" height="1" alt=""><hr><p><a href="https://medium.com/expressionengine-cms/using-ci-model-to-improve-your-expressionengine-add-ons-8d34d7ac5562">Reduce the cost of maintaining your ExpressionEngine add-ons with CI_Model</a> was originally published in <a href="https://medium.com/expressionengine-cms">ExpressionEngine Pros</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Building an API for your Add-ons with ExpressionEngine (and the A-Team)]]></title>
            <link>https://medium.com/expressionengine-cms/building-an-api-for-your-add-ons-with-expressionengine-and-the-a-team-85c1c9bc9e2c?source=rss----8bef2d56cca6---4</link>
            <guid isPermaLink="false">https://medium.com/p/85c1c9bc9e2c</guid>
            <dc:creator><![CDATA[Patrick Pohler]]></dc:creator>
            <pubDate>Tue, 29 Jul 2014 02:39:31 GMT</pubDate>
            <atom:updated>2014-09-04T02:43:59.984Z</atom:updated>
            <content:encoded><![CDATA[<h3>How to Build an API for your ExpressionEngine Add-on</h3><p>Whether you’re building an add-on for a client project or plan to sell your add-on commercially, building an API so other code can access your add-on is a great idea.</p><p>There are several advantages to building an API for your product:</p><ul><li>It can increase adoption of your software, many companies have sped up their growth by offering an API.</li><li>It allows other developers to provide future functionality and solve problems using your core product.</li><li>It leads to better code; you are forced to think about the issues other developers will face in using your software. This can make you a stronger developer.</li><li>Allows you to use powerful javascript frameworks like Ember, Angular and Knockout for front-end development.</li></ul><p>So how would we go about implementing an API in our add-on? First let’s talk about what makes a great API. Great APIs must be:</p><ul><li>Understandable, if it’s hard to use then no matter your features developers wont use it</li><li>Secure, you want to make sure only valid allowed programs have access and user data is protected</li><li>Versioned, you have to plan for new features without breaking apps using older code</li><li>Graceful in handling errors and send back clear and understandable error codes to help the developer using your api diagnose problems</li></ul><p>Now that let’s talk about actually building the API. For this article I created a sample add-on called the <a href="https://github.com/patpohler/EE-Mission-Tracker/blob/master/system/expressionengine/third_party/mission_tracker">A-Team Mission Tracker</a> to help my favorite soldiers of fortune track their missions.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/375/1*5O5Yzc2LFaZyFB13m0kLEg.gif" /><figcaption>“It’s the A-Team: Bodie, Doyle, Tiger, Jewelry Man, the whole lot!”</figcaption></figure><p>So how are external apps going to communicate to our ExpressionEngine add-on? We’ll need to make sure we can expose API methods that respond correctly to GET and POST requests. Typically in CodeIgniter you would simple create a route to respond to API requests, however ExpressionEngine overrides CI’s routing to route requests to EE’s controllers. There’s no way to get around it without making modifications to EE’s core files.</p><p>Since modifying core EE files is out of the question for our add-on, we have to find other way. Actions are how EE runs code in core and third party add-ons, they support GET &amp; POST requests and can render JSON &amp; XML.</p><p>This sounds great, unfortunately there’s a major problem with EE Actions. Here’s what they look like:</p><blockquote><a href="http://www.a-team.com/index.php?ACT=23">http://www.a-team.com/index.php?ACT=23</a></blockquote><blockquote><a href="http://www.a-team.com/index.php?ACT=33">http://www.a-team.com/index.php?ACT=33</a></blockquote><blockquote><a href="http://www.a-team.com/index.php?ACT=99">http://www.a-team.com/index.php?ACT=99</a></blockquote><p>Can you tell just from looking what API methods these URLs map to? Actions fail the “Understandable” criteria big time. Also, Action IDs vary from environment to environment and there’s no way to easily distribute it to other developers.</p><p>Fortunately there’s a way to call our API methods without having to use Actions or modify EE core. The key is to use EE’s “<a href="http://ellislab.com/expressionengine/user-guide/development/extension_hooks/global/session/index.html#sessions-start">sessions_start</a>” extension hook which fires every time a request is made.</p><p>Using this extension in the Mission Tracker add-on is as easy as creating an extension class, <a href="https://github.com/patpohler/EE-Mission-Tracker/blob/master/system/expressionengine/third_party/mission_tracker/ext.mission_tracker.php">Mission_tracker_ext</a>, and with a method that will respond to the session_start extension hook.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/957/1*FoRyFsQXGohLH62c6oQfng.png" /></figure><p>To explain this method, let’s assume the following GET request is sent to EE, “/api/mission/show_all”:</p><ul><li>Line 29: checks the first url segment against an API trigger word (“api”) if it doesn’t match we ignore the request, otherwise we move on to</li><li>Line 34-35: we check the second url segment (“mission”) if there’s a match it calls <a href="http://ellislab.com/codeigniter/user-guide/libraries/loader.html">CodeIgniter’s loader class</a> (also available in EE). We use the actual segment for our class name. In this example we’re loading the “Mission_lib” API class.</li><li>Line 38: finally we call the “call_method” method and pass it segment 3 (“show_all”), “call_method” will then go into the Mission_lib class and execute the “show_all” method returning a JSON formatted response of missions.</li></ul><p>Let me explain the loader class in detail, you can see we passed in a third parameter to “load-&gt;library()” on line 35, this powerful parameter let’s us dynamically load any library we want and define a bookmark to it, for example “mission_api.”</p><p>Then in line 38, we just use “mission_api” to refer to our class, as long as the class has a “call_method” method, we’re able to use it.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/711/1*kLD39iDDjw7MjQCUWdf2Sg.png" /></figure><p>Remember how we said call_method will actually run the API method in the loaded class? Line 21 is how it does it, PHP will execute the $method variable in the class.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/504/1*54RLwaJfnk58XLFZDgNbtw.png" /></figure><p>By organizing the API around “trigger/resource/method” we can extend the API simply by adding more resource classes (ex. Equipment_lib, Vehicle_lib) and route_url doesn’t change. As long as the resource class implements the call_method method route_url can use it. In order to make it easy, I put the call_method function in a base class that the rest of my resource classes extend.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/604/1*DnszDr6BDqXnofCgrkZpvg.png" /></figure><p>There’s a lot I didn’t cover in this article, some notes about security and other best practices:</p><ul><li>You can go deeper to secure your API, but at the very least create randomly generated API keys for registered apps. Force the apps to send the get in POST requests (you want to avoid using URLs as the key can be written to server logs). Reject requests that don’t have the proper key</li><li>Use SSL, or HTTPS. It won’t completely prevent man in the middle attacks, but it makes them harder</li><li>Use EE’s input &amp; db libraries instead of raw PHP code to process forms and save data to the db. Be paranoid about any input you get from your API and be extremely narrow what data you’ll accept</li><li>Use CodeIgniter models so your API code can use the same business logic as the rest of your module</li><li>Organize your code into libraries for reusability, move common code for your API into base classes.</li></ul><p>Finally here are a few tools to help you debug and test your API:</p><ul><li><a href="http://jsonlint.com/">JSONLint</a> to validate/test JSON is valid</li><li><a href="http://www.getpostman.com/">Postman</a> is a REST client for Chrome, send &amp; receive HTTP request &amp; responses, very good tool for quick inspection of your API without having to right an app. Although I’d highly recommend learning PHPUnit or SimpleTest and writing real unit tests.</li><li>For Windows there’s <a href="http://www.telerik.com/fiddler">Fiddler</a> which is an amazing powerful tool for debugging HTTP requests &amp; responses. It can do security and man-in-the-middle attack tests and has a number of advanced features.</li></ul><p>I hope this is enough to get you started in the world of APIs and how you can implement them for your ExpressionEngine add-ons.</p><p><em>Patrick is the owner of the development agency </em><a href="http://www.anecka.com/"><em>Anecka</em></a><em>. He also writes articles and guides for freelancers to help improve their development productivity at </em><a href="http://www.patpohler.com/"><em>PatPohler.com</em></a><em>.</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=85c1c9bc9e2c" width="1" height="1" alt=""><hr><p><a href="https://medium.com/expressionengine-cms/building-an-api-for-your-add-ons-with-expressionengine-and-the-a-team-85c1c9bc9e2c">Building an API for your Add-ons with ExpressionEngine (and the A-Team)</a> was originally published in <a href="https://medium.com/expressionengine-cms">ExpressionEngine Pros</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Turbo-charge your ExpressionEngine Add-Ons with Composer]]></title>
            <link>https://medium.com/expressionengine-cms/turbo-charge-your-expressionengine-add-ons-with-composer-2c143b83dedd?source=rss----8bef2d56cca6---4</link>
            <guid isPermaLink="false">https://medium.com/p/2c143b83dedd</guid>
            <dc:creator><![CDATA[Patrick Pohler]]></dc:creator>
            <pubDate>Fri, 25 Jul 2014 01:55:17 GMT</pubDate>
            <atom:updated>2014-09-04T02:46:25.183Z</atom:updated>
            <content:encoded><![CDATA[<p>I consider <a href="https://getcomposer.org/">Composer</a> to be one of the greatest gifts to PHP development in the last decade. If you’re not familiar, Composer is a dependency manager for PHP and I’m about to change your life. ☺</p><p>So what is a “dependency manager” anyway? I hate that term, because while it’s technically correct it’s a very dull way to describe something that’s so freaking magical. So let me state it in better terms.</p><p>Remember in the Matrix how the characters could just download certain skills into their brains and they’d instantaneously have that skill-set in the Matrix? So if one of the characters wanted to fly a helicopter all they’d have to say is “I need to fly that Huey” and BAM they could fly that particular helicopter.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/200/1*-LRHLY2WZKeTN9Aii0OvWA.jpeg" /><figcaption>Slap a pink fuzzy mustache and I can make bank as Lyft driver.</figcaption></figure><p>Now in order to fly not only do you need to know all there is to know about basic flight, but you’ll need hundreds of other smaller skills related to the very particular art of flying that model of aircraft (helicopters fly very differently than airplanes). Can you imagine how exhausting it would have been to ask and load all those particular skills (in the right order!) in an emergency? Also different characters might have had different levels of training previously that would apply to flying that would have to be worked out. It would have been almost impossible for the characters to remember and rattle them off before getting killed.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/360/1*9ioKwBuyMWOToWYa670JQA.jpeg" /><figcaption>That’s a lot of time spent on Source Forge</figcaption></figure><p>Fortunately the Matrix was equipped with a very good dependency manager so all the operator on the other end had to do was to load the Huey helicopter program and the Matrix would figure out the rest.</p><p>That’s what Composer does, anytime you want to load a particular library in your add-on it figures out any other libraries it depends on for you and installs it on your system.</p><p>I won’t go into the details on how to install and use composer, but it’s shockingly easy to install and there are <a href="https://getcomposer.org/doc/00-intro.md">very good docs here</a>.</p><p>Instead let’s skip ahead to using them in an add-on. I’m building an ExpressionEngine add-on to work with the API product I’m building called <a href="http://www.retsrabbit.com/">Rets Rabbit</a>.</p><p>The Rets Rabbit API has a client PHP library to help developers quickly use the API. It’s open source and <a href="https://github.com/patpohler/retsrabbit-php-sdk">located on GitHub</a>.</p><p>Normally if I wanted to use the library in EE I would just download the source code and copy it to “libraries” folder in my add-on’s file structure. Unfortunately the PHP library also depends on <a href="https://github.com/guzzle/guzzle">Guzzle</a> so I would have to find and download that library too (and it’s dependent libraries).</p><p>Instead I create a simple composer.json file in my add-on directory with the following text:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/463/1*NF1elaDzeFm0oi4jTtNFeA.png" /></figure><p>After saving the file all I need to do it simply run “sudo php composer install” while in my add-on directory.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/559/1*9CmGrreO_k_7CA3bryXXUA.png" /></figure><p>Composer then creates a “vendor” folder in your directory containing the third-party library and any other needed files.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/476/1*pb_KWCmsFe74M13xe8_DZw.png" /></figure><p>It also creates an “autoload.php” file that you can use to load your library. Using this in your ExpressionEngine add-on is as easy as using ‘require’</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/610/1*EeFRlg0EHteICR4FqjBS_Q.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/654/1*U-xQFiaMqP70NrJbf_lLGA.png" /></figure><p>Composer knows how to download and install Rets Rabbit PHP client by checking <a href="https://packagist.org/">Packagist.org</a>, which is a global repository of all of the publicly available composer packages.</p><p>The most powerful thing about Composer + Packagist is that allows PHP developers to quickly publish and share libraries. This allows developers to focus on making a great add-on without wasting a lot of time re-inventing solutions to problems that have already been solved.</p><p>Creating a package for the Rets Rabbit PHP library was really easy. All it required was again to create a composer.json file with a name and description of the package (and any dependencies it required).</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/430/1*hL8Fpsf5-jw_MgWlRtI0Tw.png" /></figure><p>Once I checked in this file into my GitHub repository all I had to do was submit the package on Packagist and it became publicly available.</p><p>If you’re a PHP developer, especially an ExpressionEngine add-on dev, I hope you give Composer a try. If you have a few handy libraries that are already open sourced and on GitHub consider making them into Composer packages for others.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/853/1*A8WMuKC3iPvfH0v1YaycPg.png" /><figcaption>require ‘neo/kung-fu’</figcaption></figure><p><em>Patrick is the owner of the development agency </em><a href="http://www.anecka.com/"><em>Anecka</em></a><em>. He also writes articles and guides for freelancers to help improve their development productivity at </em><a href="http://www.patpohler.com/"><em>PatPohler.com</em></a><em>.</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=2c143b83dedd" width="1" height="1" alt=""><hr><p><a href="https://medium.com/expressionengine-cms/turbo-charge-your-expressionengine-add-ons-with-composer-2c143b83dedd">Turbo-charge your ExpressionEngine Add-Ons with Composer</a> was originally published in <a href="https://medium.com/expressionengine-cms">ExpressionEngine Pros</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
    </channel>
</rss>