ZF2 Routing Explained

When a site user enters a URL in a web browser, the request is finally dispatched to controller’s action. ZF2-based application maps page URLs to controllers and their actions. This mapping is accomplished with the help of routing. Routing is implemented as a part of Zend\Mvc component.

URL Structure

To better understand routing, we first need to look at the URL structure. A typical URL from an HTTP request consists of segments. The segments are URL parts delimited by slash characters (‘/’): there are scheme, host name, path and query segments.

For example, let’s look at the URL http://site1.yourserver.com/path/to/page?query=Search

This URL begins with a scheme segment (the scheme typically looks like http or https). Then, the host name segment follows which is the domain name of your web server (like site1.yourserver.com). Optional path segments follow the host name. So if you have the path part “/path/to/page” then “path”, “to”, and “page” would each be a URL segment. Next, after the question mark, the optional query part follows. It consists of one or several “name=value” parameters separated from each other by an ampersand character (‘&’).

Each segment in a URL uses special character encoding, which is named the URL encoding. This encoding ensures that the URL contains only “safe” characters from the ASCII table. If a URL contains unsafe characters, they are replaced with a percentage character (‘%’) followed by two hexadecimal digits (for example, the space character will be replaced by ‘%20’).

Route Types

Routing is a mechanism which allows to map HTTP request to the controller.
With routing, ZF2 knows which of the controller’s action method to execute
as the result of the request. For example, you can map http://localhost/ URL to IndexController::indexAction() method or http://localhost/about URL to IndexController::aboutAction() method.

A typical routing rule has the name, type and options. The name is used to uniquely identify the rule. The type defines the name of the PHP class which implements the algorithm used for comparing the URL string. The options is an array that includes the route string which should be compared against the URL string, and several parameters called the defaults.

In general, the routing algorithm may use any data from HTTP request for matching the route. However, typically, it takes only the URL string (or its substring) as input. The algorithm then compares the URL with the route, and if the URL string matches the route, returns several parameters, including the controller’s name and action method’s name, and possibly others. These parameters may be either hard-coded in a configuration file or grabbed from the URL string. If a certain parameter cannot be retrieved from the URL, its default value is returned.

There are several standard route types provided by Zend Framework 2. These route types are implemented as classes living in the Zend\Mvc\Router\Http namespace.

  • Literal Exact matching against a path part of a URL.
  • Segment Matching against a path segment (or several segments) of a URL.
  • Regex Matching the path part of a URL against a regular expression template.
  • Wildcard Matching the path part of a URL against a key/value pattern.
    Hostname Matching the host name against some criteria.
  • Scheme Matching URL scheme against some criteria.
  • Method Matching an HTTP method (e.g. GET, POST, etc.) against some criteria.

Each route type above (except the Method type) may be matched against a specific segment (or several segments) of a URL. The Method route type is matched against the HTTP method (either GET or POST) retrieved from HTTP request.

There is also the Query route type, which is declared deprecated and is not
recommended to use. This route type is actually not needed, because you can
retrieve query parameters from your URL with the Params controller plugin.

As an example of route definition, let’s consider the Literal route type.

Literal Route Type

With Literal route type, the route match is achieved only when you have the
exact literal match of the route string against the URL path. You typically use the Literal type for URLs which should be short and memorable, like ‘/about’ or ‘/news’.

Below, the definition of the route named “home” is presented. The “home” route is
usually mapped to the “index” action of the IndexController and points to the Home page of your site:

'home' => array(
'type' => 'Zend\Mvc\Router\Http\Literal',
  'options' => array(
    'route'    => '/',
    'defaults' => array(
      'controller' => 'Application\Controller\Index',
      'action'     => 'index',

Line 2 of this example says that the route’s type is Literal. The actual
route matching algorithm is implemented in the Zend\Mvc\Router\Http\Literal
class. You can either specify the full class name or its short alias (Literal).

Line 4 defines the route string to match against the URL path (the forward slash ‘/’ means the empty URL part). Because we have the literal route type, the route match is achieved only when you have the exact literal path match. For example, if you have the URL http://localhost/ or http://localhost, it will match the ‘/’ route string.

Lines 5-8 define the defaults, which are the parameters returned by the router
if the route matches. The controller and action parameters define the controller and controller’s action method which should be executed. You can also define other parameters here, if needed.

Note: this post is an excerpt from Chapter 5 “URL Routing” of my book Using Zend Framework 2.


1 Comment

Filed under Zend Framework 2

Autoloading in Zend Framework 2

A web application consists of many PHP classes, and each class typically resides in a separate file. This introduces the need of including the files.

For example, let’s assume we have the file named Application.php which contains the definition for the \Zend\Mvc\Application class. Before you can create an instance of the Application class somewhere in your code, you have to include the contents of Application.php file (you can do this with the help of require_once statement, passing it the full path to the file):

require_once "/path/to/zend/lib/Application.php";

use Zend\Mvc\Application;

$application = new Application;

As your application grows in size, it may be difficult to include each needed file. Zend Framework 2 itself consists of hundreds of files, and it can be very difficult to load the entire library and all its dependencies this way. Moreover, when executing the resulting code, PHP interpreter will take CPU time to process each included file, even if you don’t create an instance of its class.

To fix this problem, in PHP 5.1, the class autoloading feature has been ntroduced.
The PHP function spl_autoload_register() allows you to register an autoloader function. For complex web sites, you even can create several autoloader functions, which are chained in a stack.

During script execution, if PHP interpreter encounters a class name which has not been defined yet, it calls all the registered autoloader functions in turn, until either the autoloader function includes the class or “not found” error is raised. This allows for “lazy” loading, when PHP interpreter processes the class definition only at the moment of class invocation, when it is really needed.

To give you an idea of how an autoloader function looks like, below we provide a
simplified implementation of an autoloader function:

// Autoloader function.
function autoloadFunc($className) {
  // Class map static array.
  static $classMap = array(
    'Zend\\Mvc\\Application' => '/path/to/zend/dir/Zend/Mvc/Application.php',
    'Application\\Module' => '/path/to/app/dir/Application/Module.php',

  // Check if such a class name presents in the class map.
  if(isset(static::$classMap[$className])) {
    $fileName = static::$classMap[$className];
    // Check if file exists and is readable.
    if (is_readable($filename)) {
      // Include the file.
      require $filename;

// Register our autoloader function.

In the above example, we define the autoloadFunc() autoloader function, which we will further refer to as the class map autoloader.

The class map autoloader uses the class map for mapping between class name and absolute path to PHP file containing that class. The class map is just a usual PHP
array containing keys and values. To determine the file path by class name, the class map autoloader just needs to fetch the value from the class map array. It is obvious, that the class map autoloader works very fast. However, the disadvantage of it is that you have to maintain the class map and update it each time you add a new class to your program.

PSR-0 Standard

Because each library’s vendor uses its own code naming and file organization conventions, you will have to register a different custom autoloader function per each dependent library, which is rather annoying (and actually this is an unneeded work). To resolve this problem, the PSR-0 standard was introduced.

The PSR-0 standard (PSR stands for PHP Standards Recommendation) defines the recommended code structure that an application or library must follow to guarantee autoloader interoperability. In two words, the standard says that:

  • The class namespaces should be organized in the following way:
\<Vendor Name>\(<Namespace>)*\<Class Name>
  • Namespaces can have as many nesting levels as desired, but the Vendor Name should be the top-level namespace.

  • Namespaces should map to directory structure. Each namespace separator (‘\’) is converted to a OS-specific DIRECTORY_SEPARATOR constant when loading from the file system.

  • The class name is suffixed with .php extension when loading the file from the file system.

For example, for the Zend\Mvc\Application class, you will have the following directory structure:


For the code conforming to the PSR-0 standard, we can write and register an autoloader, which we will refer to as the “standard” autoloader:


// "Standard" autoloader function.
function standardAutoloadFunc($className) {
  // Replace special characters in class name.
  $className = str_replace('\\', '/', $className);
  // Format the file path.
  $fileName = "path/to/zend/dir/" . $className . ".php";
  // Check if file exists and is readable.
  if (is_readable($fileName)) {
    // Include the file.
    require $fileName;

// Register the autoloader function.

The standard autoloader works as follows. Assuming that the class namespace can be mapped to the directory structure one-by-one, the function calculates the path to PHP file by transforming back-slashes (namespace separators) to forward slashes (path separators) and concatenating the resulting path with the absolute path to the directory where the library is located. Then the function checks if such a PHP file really exists, and if so, includes it with the require statement.

It is obvious, that the standard autoloader works slower than the class map autoloader. However, its advantage is that you don’t need to maintain any class map, which is very convenient when you develop new code and add new classes to your application.

Zend Framework 2 conforms to PSR-0 standard, making it possible to use standard autoloading mechanism across all its components. It is also compatible with other PSR-0 conforming libraries like Doctrine or Symfony 2.

Note: This post is an excerpt from my Using Zend Framework 2 e-book.

Leave a comment

Filed under Zend Framework 2

Domain Driven Design (DDD) Concepts in ZF2

Domain Driven Design (DDD) is a pattern used in programming. With DDD, you are able to model the program to best map to your problem domain.

For example, assume that you need to develop a web site intended for selling goods from a catalog to a site visitor. By applying the DDD pattern, you will have the User entity that has some properties (username, password, etc.) and behaviors (it can log in and buying some item). Additionally, you will have an Item entity which is stored in a Catalog repository, the Order entity which represents user’s order. For international web sites, you might also need the CurrencyConverter service which will convert MoneyAmount value objects to the local currency of the User.

By having these entities, value objects, services and repositories, you will better understand the mapping between your business domain and its model implemented in the web site’s code.

DDD and Zend Framework 2

For me, Domain Driven Design is still one of the most obscure things related to development with Zend Framework 2. There is still not much good tutorials on this topic. In this post, I want to summarize my knowledge about DDD.

ZF2 uses the Model-View-Controller pattern. Based on that pattern, all the code the site consists of, can be divided into three group:

  • Controllers – responsible for getting user input from GET and POST variables and pass it to model layer;
  • Models – responsible for processing the input data based on site-specific business logic algorithms and produce some output data;
  • Views – responsible for generating the HTML code based on the output data returned by models.

In Zend Framework 2, by convention, you will have model layer further splitted into entities (classes mapped on database tables), repositories (classes used to retrieve entities), value objects (model classes not having identity), services (classes responsible for business logics). Additionally, you will have forms (classes responsible for collecting user input), view helpers (reusable plugin classes intended for rendering stuff) and others.

DDD Resources

For a beginner Zend Framework 2 developer, I would recommend the following two resources:

A short intro to Domain Driven Design can be found in this PDF by InfoQ: Domain Driven Design Quickly

Recently, I’ve watched the webinar called An introduction to Domain Driven Design with ZF2 (you will need to log into your Zend account to watch the webinar).

ZF2 Model Types

In Zend Framework 2, there is no single Model directory for storing the model classes. Instead, by convention, models are further subdivided into the following types, and each type is stored in its own subdirectory (see table below):

Model Type Directory
Entities APP_DIR/module/Application/src/Application/Entity
Value Objects APP_DIR/module/Application/src/Application/ValueObject
Services APP_DIR/module/Application/src/Application/Service
Repositories APP_DIR/module/Application/src/Application/Repository
Factories APP_DIR/module/Application/src/Application/Factory

Separation of models into different types makes it easier to design your business logic domain. This is also called the “Domain Driven Design” (or shortly, DDD). The person who proposed DDD was Martin Fowler in his famous book called Patterns of Enterprise Application Architecture.


Entities always have some identifier property, so you can uniquely identify the object. For example, a User entity always has a unique login property, and you can identify the user by that attribute. You can change some other attributes of the entity, like firstName, or address, but its identifier never changes. Entity models are usually stored in a database, in a file system or in any other storage.

Below, you can find an example a User entity, which represents a site visitor:

// The User entity represents a site visitor
class User {

  // Properties
  private $login;     // e.g. "admin"
  private $title;     // e.g. "Mr."
  private $firstName; // e.g. "John"
  private $lastName;  // e.g. "Doe"
  private $country;   // e.g. "USA"
  private $city;      // e.g. "Paris"
  private $zipCode;   // e.g. "10543"
  private $address;   // e.g. "Jackson rd."
  // Behaviors    
  public getLogin() {
    return $this->login;
  public setLogin($login) {
    $this->login = $login;

In lines 5-10, we define User model’s properties. The best practice is to
define the properties using the private access type, and make
them available to the caller through getter and setter public methods
(like getLogin() and setLogin(), etc).

Model’s behavior methods are not limited by getters and setters.
You can create other methods which manipulate with model’s data.
For example, you can define the getFullName() convenience method,
which would return the user’s full name, like “Mr. John Doe”.

Value Objects

Value objects are a kind of model for which the identity is not as important as for entities. A value object is usually a small class identified by all of its attributes. It does not have an identifier attribute. Value objects typically have getter methods, but do not have setters (value objects are immutable).

For example, a model wrapping a money amount can be treated as a value object:

class MoneyAmount {
  // Properties
  private $currency;
  private $amount;
  // Constructor
  public function __construct($amount, $currency='USD') {
    $this->amount = $amount;
    $this->currency = $currency;
  // Gets the currency code  
  public function getCurrency() {
    return $this->currency;  
  // Gets the money amount
  public function getAmount() {
    return $this->amount;
  // Converts the money amount into new currency
  public static function convert($newCurrency) {
    // Use currency exchange rates algorithm to determine the
    // new amount.
    if($this->currency=='USD' && $newCurrency=='EUR') {
      $newAmount = 1.1*$this->amount;
      return new MoneyAmount($newAmount, $newCurrency); 
    } else {
      throw new Exception('Unknown currency code');

In lines 4-5 we define two properties: currency and amount. The model has no identifier property, instead it is identified by all properties as a whole: if you change either the currency or amount, you would have a different money amount object.

In lines 8-10 we define the constructor method, which initializes the properties. In lines 14-21, we define getter methods for model’s properties. Note that we do not have setter methods (the model is immutable).

In lines 24-33 we have the static method convert(), which is designed to convert money amount to another currency using some simple currency conversion algorithm. Instead of modifying the money amount properties, it constructs and returns a new MoneyAmount object.

The real life is much more difficult than we described above, and you should be “flexible” enough to adapt your entities and value objects to real conditions. In some situations you will have a value object which is “mutable” (have setter methods), and sometimes, you will have only getter methods for some of entity properties. Do not dwell on the idealistic recommendations provided by others, instead adapt your models as your intuition advices to you.


Service models usually encapsulate some business logic functionality. Services typically do not have state (internal properties), instead they manipulate other entity models and value objects. Services usually have easily recognizable names ending with “er” suffix, like FileUploaderService or UserManagerService.

Below, an example of MailerService service is presented. It has the sendMail()
method which takes an EmailMessage value object and sends an E-mail message using standard PHP mail() function:

// The Email message value object
class EmailMessage {  
  private $recipient;
  private $subject;
  private $text;  
  // Constructor
  public function __construct($recipient, $subject, $text) {
    $this->recipient = $recipient;
    $this->subject = $subject;
    $this->text = $text;
  // Getters
  public function getRecipient() {
    return $this->recipient;
  public function getSubject() {
    return $this->subject;
  public function getText() {
    return $this->text;

// The Mailer service, which can send messages by E-mail
class MailerService {
  public function sendMail($message) {
    // Use PHP mail() function to send an E-mail
    if(!mail($message->getRecipient(), $message->getSubject(), 
      // Error sending message
      return false
    return true;


Factories are usually being designed to instantiate other models. In the simplest cases you can create an instance of a class without any factory, just by using the new operator, but sometimes class creation logic might be very complex, and you encapsulate it inside of a factory class. Factory classes typically have names ending with Factory suffix, like ResourceFactory, FileFactory, etc.

For example, let’s consider the case when you use a CAPTCHA image in a web form. The image is a type of challenge-response test used to determine whether the user is a human or a robot.

There may be different CAPTCHA types: simple image captcha, reCAPTCHA and so on. Let’s create a fictitious CaptchaFactory class, whose only goal is to create different CAPTCHA images based on the $type argument you pass to its createCaptcha() method.

// The CaptchaFactory class is used to create CAPTCHA
// image for a web form.
class CaptchaFactory {

  // Creates a CAPTCHA object based on type parameter
  public static function createCaptcha($type) {
      return new ImageCaptcha();
    else if($type=='ReCaptcha')
      return new ReCaptcha();
      throw new Exception('Unknown captcha type');


Repositories are specific models responsible for storing and retrieving entities.
For example, a UserRepository may represent a database table and provide methods
for retrieving User entities. You typically use repositories when storing entities
in a database. With repositories, you can encapsulate SQL query logic in the
single place and easily maintain and test it.

Note: This post is an excerpt of my Using Zend Framework 2 e-Book.


Filed under Zend Framework 2

When to Create a New Controller in ZF2?

When your site grows in size, you should create new controller classes instead of putting all actions to IndexController. The Index controller is used for defining the actions which work for your entire site. It is recommended to create new controller class for each model (or for most important ones) of your business logic domain.

For example, you can create UserController to manage users of your site. This controller would have the default “index” action for displaying the page with all users, “add” action for adding a new user, “edit” action for editing user’s profile and “delete” action for deleting the user.

By analogy, you would create PurchaseController and its actions to manage the purchases of your products and implementing the shopping cart, DownloadController and its actions to manage file downloads for the site, etc.

Controller Registration

All controller classes belonging to a module should be registered in the module.config.php
configuration file as follows:

return array(
  // ...
  'controllers' => array(
    'invokables' => array(
      'Application\Controller\Index' => 
      // Put other controllers registration here
  // ...

In line 5, we have the the controllers key, which contains the invokables subkey. You should register your controllers here. To register a controller class, you add the line in form of key=>value pair. The key should be the unique ID of the controller, like Application\Controller\Index, and value should be the fully qualified class name of the controller, like Application\Controller\IndexController.

By registering your controller under the invokables subkey, you tell Zend Framework that it can invoke the controller by instantiating it with the new operator. This is the most simple way of instantiating the controller. As an alternative, you can register a factory to create the controller instance, in that case you would register your controller under the factories subkey.

Leave a comment

Filed under PHP, Zend Framework 2

The Best Zend Framework 2 Book

This poll is indended to determine the best Zend Framework 2 book. Indicate books about Zend Framework 2 that you have read and found easy to read, interesting and useful for you. You can vote only one time. Multiple choices are allowed.

Leave a comment

Filed under Zend Framework 2

PHPCloud — A New Easy Way to Run ZF2 Web Applications

In this post, I will tell about the PHPCloud, which is a new “platform as a service” which makes it possible to run your Zend Framework 2 based application in the cloud. The PHPCloud is currently in beta testing stage and available for free test usage. I think it is the best time to try it and become familiar with the capabilities provided by the service.

Why to Use PHPCloud?

Today, there are several options available of where you can install and run your Zend Framework 2 based web application:

  1. If your company manages its own server infrastructure and can afford upgrading PHP version to the latest one, you can install ZF2 on your private server.

  2. You can install a ZF2-based web application to a cloud-based hosting service, like Amazon Web Services. Amazon provides Linux server instances as a part of EC2 service. EC2 is rather cheap, and it provides a free usage tier letting you try it for free for one year.

  3. And the third alternative is installing a ZF2-based application is PHP Cloud. This “platform as a service” solution was introduced by Zend Technologies recently. PHP Cloud allows you to develop and install one or several of your web sites in a cloud container.

In this post, I will tell about the third way, which is the easiest one (in my opinion). This way is analogous to Amazon EC2 hosting service, but it automatically provides you with the hardware, operating system, web server and MySQL database, so you can just create a container and start working in a minute. By working, I mean creating an empty ZF2 application, opening it in your web browser and updating the code from your machine.

The difference of the PHPCloud service from Amazon EC2 is that you do not have direct access to the server through SSH terminal. Instead, you will update your code repository throug Git version control system’s client.

Creating a Container

In PHPCloud, web applications are installed to a container. You can imagine the container like a virtual machine with PHP engine installed. One user may have one or more containers. Next I will show how you create a container.

First, you have to log into your Zend account at the https://my.phpcloud.com/user/login page. This is a page which provides access to BETA version of the PHPCloud and is free for test usage.

To log into your account, you need to enter your E-mail and password and click the Log in button (see the figure below for example). If you do not have an account, you will have to register and enter your E-mail address and password.


Once you have logged in, you will see the Welcome page (shown in figure below).


The Welcome page introduces you to the PHPCloud and lists its advantages: you can start coding in a minute and upload your ZF2 application via Git version control system.

Press the Start Now button at the right part of the Welcome page to open the “Create Container” page (shown in figure below):


On the “Create Container” page that appears, you will have to enter the container name (it must be unique among all other container names). Also, you will be asked to enter the container password (you will later use this password for accessing your container with Git client. You can choose a PHP version (5.3 or 5.4) and configure an SMTP server if you want to send E-mails from your web application.

Once you are ready, click the “Create Container” button to trigger the container creation process.

The next page is the “My Containers” page that lists the containers you have already created:

On the “My Containers” page, you can see the container you’ve just created. You can also request to create the second test container, if you wish. In this post, I will use the single container.

The “My Containers” page has the Snapshot, Revert and Delete buttons. The Snapshot button allows you to make a backup copy of the container if you need that. The Revert button is designed to roll back the container to one of its previous states (like you do in a version control system). And, the Delete button allows to remove container.

After creation, your container already has the default web application installed. To see that default application, click the link next to container name (in this example the link is olegkrivtsov.my.phpcloud.com). The web page appears like in figure below:


On the page that appears, you can see that the default application is just a stub that offers you to upload some code and start working on your own web site.

Deploying Zend Skeleton Application

Next, I will show how to deploy an empty Zend Skeleton Application in the container we have just created.

On the My Containers page, click the container name link to enter into the container’s Dashboard page (in this example, the container’s name is olegkrivtsov). The Dashboard page appears where you can manage your container (shown in figure below):


On the Dashboard page, open the the PHPCloud->Overview tab. Then click the Deploy New Application link.

In the pop-up window that appears, you need to choose application type (in this example, I choose “Empty Zend Framework 2 Application”). Click the Next button.


On the next page (shown in figure below), choose the application name (in this example, I enter the “skeleton” name).


Here, you will also need to enter the path to the application which is the part of the URL that allows to open your web app in a web browser. In this example, I use the “skeleton” path. As you are ready, click the Deploy New Application button.

Next, you can see you application in the list of installed application on the Dashboard page. Clicking the application name opens it in the web browser (see the figure below):


Alternatively, you can see your installed skeleton application in the web browser by entering the following URL into its address bar: http://olegkrivtsov.my.phpcloud.com/skeleton. In the URL, the “olegkrivtsov” part is the name of the container, and the “skeleton” is the path to the web application.

Congratulations! We have just deployed our Zend Skeleton Application from scratch and ready to modify its code and develop our own ZF2 based web site.

Using GIT to Update Code in Container

In the last part of this post, I will show how you can connect to your container with the Git client and update the code.

When using Git, you typically make a clone of the code stored in the container, work on it and commit your changes locally, and then push the code back to the container. The Git version control system stores the complete history of the changes you made, so you can roll back your container to any of its previous states. This makes it easy to safely update the code and work on large web applications in a team.

If you don’t have a Git client on your machine yet, I would recommend you to install Tortoise Git that is a convenient graphical Git client for Windows.

To connect to the Git code repository associated with your PHPCloud container, you will need two things: the URL of the repository and a private RSA key.

First, we will obtain the private key. On the Dashboard page, click the Access Keys page. The Access Keys page appears where you can generate a new key pair (see figure below for example).


To do that, in the dropdown list, select the PPK (WinSCP and PuTTY on Windows) option and click the Generate New Keypair button. The PPK private key file then will be downloaded to your machine.

To obtain the Gir repository URL, on the Dashboard page, click the application name (“skeleton” in this example). The popup pane appears (shown in figure below).


On that pane, click the GIT Repository tab. Here you can see two URLs: the first one is the URL for accessing your repository via SSH (recommended), and the second one is for accessing it via HTTPS. You need to copy the first URL.

Next, in Windows Explorer, create an empty directory somewhere and name it, say, “phpcloud”. In Windows explorer, enter the empty directory you have just created and right click on empty space. The context menu appears. Choose the “GIT Clone…” item from the menu. The Git Clone windows appears (shown in figure below).


In the Git window, enter the URL of the repository and pick the PPK file.
Then click the Clone button. The cloning progress window appears:


Once the clone process finishes, you can browse the source code of the skeleton application in Windows explorer (see below for example).


With Tortoise Git, you can make changes, commit them locally and push the changes back to the PHPCloud. In other words, you can work on your web application, apply changes to the code, and see the result in your web browser, the same way you usually do.

1 Comment

Filed under PHP, Zend Framework 2

Get Your PHP Elephant Toy


I’ve found this cool site where you can buy a PHP elephant of your choice. This may be a great gift for your collegue or friend.

The link: http://get-elephpant.com/

Leave a comment

Filed under Uncategorized