diff --git a/src/applications/pholio/controller/PholioImageUploadController.php b/src/applications/pholio/controller/PholioImageUploadController.php
index 0329d3eb1d..39dd661a4a 100644
--- a/src/applications/pholio/controller/PholioImageUploadController.php
+++ b/src/applications/pholio/controller/PholioImageUploadController.php
@@ -1,43 +1,43 @@
 <?php
 
 final class PholioImageUploadController extends PholioController {
 
   public function handleRequest(AphrontRequest $request) {
     $viewer = $request->getViewer();
 
     $phid = $request->getStr('filePHID');
     $replaces_phid = $request->getStr('replacesPHID');
     $title = $request->getStr('title');
     $description = $request->getStr('description');
 
     $file = id(new PhabricatorFileQuery())
       ->setViewer($viewer)
       ->withPHIDs(array($phid))
       ->executeOne();
     if (!$file) {
       return new Aphront404Response();
     }
 
     if (!strlen($title)) {
       $title = $file->getName();
     }
 
-    $image = id(new PholioImage())
+    $image = PholioImage::initializeNewImage()
       ->attachFile($file)
       ->setName($title)
       ->setDescription($description)
       ->makeEphemeral();
 
     $view = id(new PholioUploadedImageView())
       ->setUser($viewer)
       ->setImage($image)
       ->setReplacesPHID($replaces_phid);
 
     $content = array(
       'markup' => $view,
     );
 
     return id(new AphrontAjaxResponse())->setContent($content);
   }
 
 }
diff --git a/src/applications/pholio/controller/PholioMockEditController.php b/src/applications/pholio/controller/PholioMockEditController.php
index 89d1fe2a50..9a09c9bc67 100644
--- a/src/applications/pholio/controller/PholioMockEditController.php
+++ b/src/applications/pholio/controller/PholioMockEditController.php
@@ -1,371 +1,371 @@
 <?php
 
 final class PholioMockEditController extends PholioController {
 
   public function handleRequest(AphrontRequest $request) {
     $viewer = $request->getViewer();
     $id = $request->getURIData('id');
 
     if ($id) {
       $mock = id(new PholioMockQuery())
         ->setViewer($viewer)
         ->needImages(true)
         ->requireCapabilities(
           array(
             PhabricatorPolicyCapability::CAN_VIEW,
             PhabricatorPolicyCapability::CAN_EDIT,
           ))
         ->withIDs(array($id))
         ->executeOne();
 
       if (!$mock) {
         return new Aphront404Response();
       }
 
       $title = pht('Edit Mock: %s', $mock->getName());
 
       $is_new = false;
       $mock_images = $mock->getImages();
       $files = mpull($mock_images, 'getFile');
       $mock_images = mpull($mock_images, null, 'getFilePHID');
     } else {
       $mock = PholioMock::initializeNewMock($viewer);
 
       $title = pht('Create Mock');
 
       $is_new = true;
       $files = array();
       $mock_images = array();
     }
 
     if ($is_new) {
       $v_projects = array();
     } else {
       $v_projects = PhabricatorEdgeQuery::loadDestinationPHIDs(
         $mock->getPHID(),
         PhabricatorProjectObjectHasProjectEdgeType::EDGECONST);
       $v_projects = array_reverse($v_projects);
     }
 
     $e_name = true;
     $e_images = count($mock_images) ? null : true;
     $errors = array();
     $posted_mock_images = array();
 
     $v_name = $mock->getName();
     $v_desc = $mock->getDescription();
     $v_view = $mock->getViewPolicy();
     $v_edit = $mock->getEditPolicy();
     $v_cc = PhabricatorSubscribersQuery::loadSubscribersForPHID(
       $mock->getPHID());
     $v_space = $mock->getSpacePHID();
 
     if ($request->isFormPost()) {
       $xactions = array();
 
       $type_name = PholioMockNameTransaction::TRANSACTIONTYPE;
       $type_desc = PholioMockDescriptionTransaction::TRANSACTIONTYPE;
       $type_view = PhabricatorTransactions::TYPE_VIEW_POLICY;
       $type_edit = PhabricatorTransactions::TYPE_EDIT_POLICY;
       $type_cc   = PhabricatorTransactions::TYPE_SUBSCRIBERS;
       $type_space = PhabricatorTransactions::TYPE_SPACE;
 
       $v_name = $request->getStr('name');
       $v_desc = $request->getStr('description');
       $v_view = $request->getStr('can_view');
       $v_edit = $request->getStr('can_edit');
       $v_cc   = $request->getArr('cc');
       $v_projects = $request->getArr('projects');
       $v_space = $request->getStr('spacePHID');
 
       $mock_xactions = array();
       $mock_xactions[$type_name] = $v_name;
       $mock_xactions[$type_desc] = $v_desc;
       $mock_xactions[$type_view] = $v_view;
       $mock_xactions[$type_edit] = $v_edit;
       $mock_xactions[$type_cc]   = array('=' => $v_cc);
       $mock_xactions[$type_space] = $v_space;
 
       $file_phids = $request->getArr('file_phids');
       if ($file_phids) {
         $files = id(new PhabricatorFileQuery())
           ->setViewer($viewer)
           ->withPHIDs($file_phids)
           ->execute();
         $files = mpull($files, null, 'getPHID');
         $files = array_select_keys($files, $file_phids);
       } else {
         $files = array();
       }
 
       if (!$files) {
         $e_images = pht('Required');
         $errors[] = pht('You must add at least one image to the mock.');
       } else {
         $mock->setCoverPHID(head($files)->getPHID());
       }
 
       foreach ($mock_xactions as $type => $value) {
         $xactions[$type] = id(new PholioTransaction())
           ->setTransactionType($type)
           ->setNewValue($value);
       }
 
       $order = $request->getStrList('imageOrder');
       $sequence_map = array_flip($order);
       $replaces = $request->getArr('replaces');
       $replaces_map = array_flip($replaces);
 
       /**
        * Foreach file posted, check to see whether we are replacing an image,
        * adding an image, or simply updating image metadata. Create
        * transactions for these cases as appropos.
        */
       foreach ($files as $file_phid => $file) {
         $replaces_image_phid = null;
         if (isset($replaces_map[$file_phid])) {
           $old_file_phid = $replaces_map[$file_phid];
           if ($old_file_phid != $file_phid) {
             $old_image = idx($mock_images, $old_file_phid);
             if ($old_image) {
               $replaces_image_phid = $old_image->getPHID();
             }
           }
         }
 
         $existing_image = idx($mock_images, $file_phid);
 
         $title = (string)$request->getStr('title_'.$file_phid);
         $description = (string)$request->getStr('description_'.$file_phid);
         $sequence = $sequence_map[$file_phid];
 
         if ($replaces_image_phid) {
-          $replace_image = id(new PholioImage())
+          $replace_image = PholioImage::initializeNewImage()
             ->setReplacesImagePHID($replaces_image_phid)
             ->setFilePhid($file_phid)
             ->attachFile($file)
             ->setName(strlen($title) ? $title : $file->getName())
             ->setDescription($description)
             ->setSequence($sequence);
           $xactions[] = id(new PholioTransaction())
             ->setTransactionType(
               PholioImageReplaceTransaction::TRANSACTIONTYPE)
             ->setNewValue($replace_image);
           $posted_mock_images[] = $replace_image;
         } else if (!$existing_image) { // this is an add
-          $add_image = id(new PholioImage())
+          $add_image = PholioImage::initializeNewImage()
             ->setFilePhid($file_phid)
             ->attachFile($file)
             ->setName(strlen($title) ? $title : $file->getName())
             ->setDescription($description)
             ->setSequence($sequence);
           $xactions[] = id(new PholioTransaction())
             ->setTransactionType(PholioImageFileTransaction::TRANSACTIONTYPE)
             ->setNewValue(
               array('+' => array($add_image)));
           $posted_mock_images[] = $add_image;
         } else {
           $xactions[] = id(new PholioTransaction())
             ->setTransactionType(PholioImageNameTransaction::TRANSACTIONTYPE)
             ->setNewValue(
               array($existing_image->getPHID() => $title));
           $xactions[] = id(new PholioTransaction())
             ->setTransactionType(
               PholioImageDescriptionTransaction::TRANSACTIONTYPE)
               ->setNewValue(
                 array($existing_image->getPHID() => $description));
           $xactions[] = id(new PholioTransaction())
             ->setTransactionType(
               PholioImageSequenceTransaction::TRANSACTIONTYPE)
               ->setNewValue(
                 array($existing_image->getPHID() => $sequence));
 
           $posted_mock_images[] = $existing_image;
         }
       }
       foreach ($mock_images as $file_phid => $mock_image) {
         if (!isset($files[$file_phid]) && !isset($replaces[$file_phid])) {
           // this is an outright delete
           $xactions[] = id(new PholioTransaction())
             ->setTransactionType(PholioImageFileTransaction::TRANSACTIONTYPE)
             ->setNewValue(
               array('-' => array($mock_image)));
         }
       }
 
       if (!$errors) {
         $proj_edge_type = PhabricatorProjectObjectHasProjectEdgeType::EDGECONST;
         $xactions[] = id(new PholioTransaction())
           ->setTransactionType(PhabricatorTransactions::TYPE_EDGE)
           ->setMetadataValue('edge:type', $proj_edge_type)
           ->setNewValue(array('=' => array_fuse($v_projects)));
 
         $mock->openTransaction();
         $editor = id(new PholioMockEditor())
           ->setContentSourceFromRequest($request)
           ->setContinueOnNoEffect(true)
           ->setActor($viewer);
 
         $xactions = $editor->applyTransactions($mock, $xactions);
 
         $mock->saveTransaction();
 
         return id(new AphrontRedirectResponse())
           ->setURI('/M'.$mock->getID());
       }
     }
 
     if ($id) {
       $submit = id(new AphrontFormSubmitControl())
         ->addCancelButton('/M'.$id)
         ->setValue(pht('Save'));
     } else {
       $submit = id(new AphrontFormSubmitControl())
         ->addCancelButton($this->getApplicationURI())
         ->setValue(pht('Create'));
     }
 
     $policies = id(new PhabricatorPolicyQuery())
       ->setViewer($viewer)
       ->setObject($mock)
       ->execute();
 
     // NOTE: Make this show up correctly on the rendered form.
     $mock->setViewPolicy($v_view);
     $mock->setEditPolicy($v_edit);
 
     $image_elements = array();
     if ($posted_mock_images) {
       $display_mock_images = $posted_mock_images;
     } else {
       $display_mock_images = $mock_images;
     }
     foreach ($display_mock_images as $mock_image) {
       $image_elements[] = id(new PholioUploadedImageView())
         ->setUser($viewer)
         ->setImage($mock_image)
         ->setReplacesPHID($mock_image->getFilePHID());
     }
 
     $list_id = celerity_generate_unique_node_id();
     $drop_id = celerity_generate_unique_node_id();
     $order_id = celerity_generate_unique_node_id();
 
     $list_control = phutil_tag(
       'div',
       array(
         'id' => $list_id,
         'class' => 'pholio-edit-list',
       ),
       $image_elements);
 
     $drop_control = phutil_tag(
       'a',
       array(
         'id' => $drop_id,
         'class' => 'pholio-edit-drop',
       ),
       pht('Click here, or drag and drop images to add them to the mock.'));
 
     $order_control = phutil_tag(
       'input',
       array(
         'type' => 'hidden',
         'name' => 'imageOrder',
         'id' => $order_id,
       ));
 
     Javelin::initBehavior(
       'pholio-mock-edit',
       array(
         'listID' => $list_id,
         'dropID' => $drop_id,
         'orderID' => $order_id,
         'uploadURI' => '/file/dropupload/',
         'renderURI' => $this->getApplicationURI('image/upload/'),
         'pht' => array(
           'uploading' => pht('Uploading Image...'),
           'uploaded' => pht('Upload Complete...'),
           'undo' => pht('Undo'),
           'removed' => pht('This image will be removed from the mock.'),
         ),
       ));
 
     require_celerity_resource('pholio-edit-css');
     $form = id(new AphrontFormView())
       ->setUser($viewer)
       ->appendChild($order_control)
       ->appendChild(
         id(new AphrontFormTextControl())
         ->setName('name')
         ->setValue($v_name)
         ->setLabel(pht('Name'))
         ->setError($e_name))
       ->appendChild(
         id(new PhabricatorRemarkupControl())
         ->setName('description')
         ->setValue($v_desc)
         ->setLabel(pht('Description'))
         ->setUser($viewer))
       ->appendControl(
         id(new AphrontFormTokenizerControl())
           ->setLabel(pht('Tags'))
           ->setName('projects')
           ->setValue($v_projects)
           ->setDatasource(new PhabricatorProjectDatasource()))
       ->appendControl(
         id(new AphrontFormTokenizerControl())
           ->setLabel(pht('Subscribers'))
           ->setName('cc')
           ->setValue($v_cc)
           ->setUser($viewer)
           ->setDatasource(new PhabricatorMetaMTAMailableDatasource()))
       ->appendChild(
         id(new AphrontFormPolicyControl())
           ->setUser($viewer)
           ->setCapability(PhabricatorPolicyCapability::CAN_VIEW)
           ->setPolicyObject($mock)
           ->setPolicies($policies)
           ->setSpacePHID($v_space)
           ->setName('can_view'))
       ->appendChild(
         id(new AphrontFormPolicyControl())
           ->setUser($viewer)
           ->setCapability(PhabricatorPolicyCapability::CAN_EDIT)
           ->setPolicyObject($mock)
           ->setPolicies($policies)
           ->setName('can_edit'))
       ->appendChild(
         id(new AphrontFormMarkupControl())
           ->setValue($list_control))
       ->appendChild(
         id(new AphrontFormMarkupControl())
           ->setValue($drop_control)
           ->setError($e_images))
       ->appendChild($submit);
 
     $form_box = id(new PHUIObjectBoxView())
       ->setHeaderText($title)
       ->setFormErrors($errors)
       ->setBackground(PHUIObjectBoxView::WHITE_CONFIG)
       ->setForm($form);
 
     $crumbs = $this->buildApplicationCrumbs();
     if (!$is_new) {
       $crumbs->addTextCrumb($mock->getMonogram(), '/'.$mock->getMonogram());
     }
     $crumbs->addTextCrumb($title);
     $crumbs->setBorder(true);
 
     $view = id(new PHUITwoColumnView())
       ->setFooter($form_box);
 
     return $this->newPage()
       ->setTitle($title)
       ->setCrumbs($crumbs)
       ->addQuicksandConfig(
         array('mockEditConfig' => true))
       ->appendChild($view);
   }
 
 }
diff --git a/src/applications/pholio/lipsum/PhabricatorPholioMockTestDataGenerator.php b/src/applications/pholio/lipsum/PhabricatorPholioMockTestDataGenerator.php
index 039b0ddeef..c038fcf922 100644
--- a/src/applications/pholio/lipsum/PhabricatorPholioMockTestDataGenerator.php
+++ b/src/applications/pholio/lipsum/PhabricatorPholioMockTestDataGenerator.php
@@ -1,119 +1,120 @@
 <?php
 
 final class PhabricatorPholioMockTestDataGenerator
   extends PhabricatorTestDataGenerator {
 
   const GENERATORKEY = 'mocks';
 
   public function getGeneratorName() {
     return pht('Pholio Mocks');
   }
 
   public function generateObject() {
     $author_phid = $this->loadPhabricatorUserPHID();
     $author = id(new PhabricatorUser())
           ->loadOneWhere('phid = %s', $author_phid);
     $mock = PholioMock::initializeNewMock($author);
 
     $content_source = $this->getLipsumContentSource();
 
     $template = id(new PholioTransaction())
       ->setContentSource($content_source);
 
     // Accumulate Transactions
     $changes = array();
     $changes[PholioMockNameTransaction::TRANSACTIONTYPE] =
       $this->generateTitle();
     $changes[PholioMockDescriptionTransaction::TRANSACTIONTYPE] =
       $this->generateDescription();
     $changes[PhabricatorTransactions::TYPE_VIEW_POLICY] =
       PhabricatorPolicies::POLICY_PUBLIC;
     $changes[PhabricatorTransactions::TYPE_SUBSCRIBERS] =
       array('=' => $this->getCCPHIDs());
 
     // Get Files and make Images
     $file_phids = $this->generateImages();
     $files = id(new PhabricatorFileQuery())
       ->setViewer($author)
       ->withPHIDs($file_phids)
       ->execute();
     $mock->setCoverPHID(head($files)->getPHID());
     $sequence = 0;
     $images = array();
     foreach ($files as $file) {
-      $image = new PholioImage();
-      $image->setFilePHID($file->getPHID());
-      $image->setSequence($sequence++);
-      $image->attachMock($mock);
+      $image = PholioImage::initializeNewImage()
+        ->setFilePHID($file->getPHID())
+        ->setSequence($sequence++)
+        ->attachMock($mock);
+
       $images[] = $image;
     }
 
     // Apply Transactions
     $transactions = array();
     foreach ($changes as $type => $value) {
       $transaction = clone $template;
       $transaction->setTransactionType($type);
       $transaction->setNewValue($value);
       $transactions[] = $transaction;
     }
     $mock->openTransaction();
     $editor = id(new PholioMockEditor())
       ->setContentSource($content_source)
       ->setContinueOnNoEffect(true)
       ->setActor($author)
       ->applyTransactions($mock, $transactions);
     foreach ($images as $image) {
       $image->setMockID($mock->getID());
       $image->save();
     }
 
     $mock->saveTransaction();
     return $mock->save();
   }
 
   public function generateTitle() {
     return id(new PhutilLipsumContextFreeGrammar())
       ->generate();
   }
 
   public function generateDescription() {
     return id(new PhutilLipsumContextFreeGrammar())
       ->generateSeveral(rand(30, 40));
   }
 
   public function getCCPHIDs() {
     $ccs = array();
     for ($i = 0; $i < rand(1, 4);$i++) {
       $ccs[] = $this->loadPhabricatorUserPHID();
     }
     return $ccs;
   }
 
   public function generateImages() {
     $images = newv('PhabricatorFile', array())
       ->loadAllWhere('mimeType = %s', 'image/jpeg');
     $rand_images = array();
     $quantity = rand(2, 10);
     $quantity = min($quantity, count($images));
 
     if ($quantity) {
       $random_images = $quantity === 1 ?
         array(array_rand($images, $quantity)) :
         array_rand($images, $quantity);
 
       foreach ($random_images as $random) {
         $rand_images[] = $images[$random]->getPHID();
       }
     }
 
     // This means you don't have any JPEGs yet. We'll just use a built-in image.
     if (empty($rand_images)) {
       $default = PhabricatorFile::loadBuiltin(
         PhabricatorUser::getOmnipotentUser(),
         'profile.png');
       $rand_images[] = $default->getPHID();
     }
     return $rand_images;
   }
 
 }
diff --git a/src/applications/pholio/storage/PholioImage.php b/src/applications/pholio/storage/PholioImage.php
index 70f6e8b8c4..e0b55bae10 100644
--- a/src/applications/pholio/storage/PholioImage.php
+++ b/src/applications/pholio/storage/PholioImage.php
@@ -1,122 +1,128 @@
 <?php
 
 final class PholioImage extends PholioDAO
   implements
     PhabricatorMarkupInterface,
     PhabricatorPolicyInterface {
 
   const MARKUP_FIELD_DESCRIPTION  = 'markup:description';
 
   protected $mockID;
   protected $filePHID;
-  protected $name = '';
-  protected $description = '';
+  protected $name;
+  protected $description;
   protected $sequence;
-  protected $isObsolete = 0;
+  protected $isObsolete;
   protected $replacesImagePHID = null;
 
   private $inlineComments = self::ATTACHABLE;
   private $file = self::ATTACHABLE;
   private $mock = self::ATTACHABLE;
 
+  public static function initializeNewImage() {
+    return id(new self())
+      ->setName('')
+      ->setDescription('')
+      ->setIsObsolete(0);
+  }
+
   protected function getConfiguration() {
     return array(
       self::CONFIG_AUX_PHID => true,
       self::CONFIG_COLUMN_SCHEMA => array(
         'mockID' => 'id?',
         'name' => 'text128',
         'description' => 'text',
         'sequence' => 'uint32',
         'isObsolete' => 'bool',
         'replacesImagePHID' => 'phid?',
       ),
       self::CONFIG_KEY_SCHEMA => array(
         'key_phid' => null,
         'keyPHID' => array(
           'columns' => array('phid'),
           'unique' => true,
         ),
         'mockID' => array(
           'columns' => array('mockID', 'isObsolete', 'sequence'),
         ),
       ),
     ) + parent::getConfiguration();
   }
 
-  public function generatePHID() {
-    return PhabricatorPHID::generateNewPHID(PholioImagePHIDType::TYPECONST);
+  public function getPHIDType() {
+    return PholioImagePHIDType::TYPECONST;
   }
 
   public function attachFile(PhabricatorFile $file) {
     $this->file = $file;
     return $this;
   }
 
   public function getFile() {
     $this->assertAttached($this->file);
     return $this->file;
   }
 
   public function attachMock(PholioMock $mock) {
     $this->mock = $mock;
     return $this;
   }
 
   public function getMock() {
     $this->assertAttached($this->mock);
     return $this->mock;
   }
 
-
   public function attachInlineComments(array $inline_comments) {
     assert_instances_of($inline_comments, 'PholioTransactionComment');
     $this->inlineComments = $inline_comments;
     return $this;
   }
 
   public function getInlineComments() {
     $this->assertAttached($this->inlineComments);
     return $this->inlineComments;
   }
 
 
 /* -(  PhabricatorMarkupInterface  )----------------------------------------- */
 
 
   public function getMarkupFieldKey($field) {
     $content = $this->getMarkupText($field);
     return PhabricatorMarkupEngine::digestRemarkupContent($this, $content);
   }
 
   public function newMarkupEngine($field) {
     return PhabricatorMarkupEngine::newMarkupEngine(array());
   }
 
   public function getMarkupText($field) {
     return $this->getDescription();
   }
 
   public function didMarkupText($field, $output, PhutilMarkupEngine $engine) {
     return $output;
   }
 
   public function shouldUseMarkupCache($field) {
     return (bool)$this->getID();
   }
 
 /* -(  PhabricatorPolicyInterface Implementation  )-------------------------- */
 
   public function getCapabilities() {
     return $this->getMock()->getCapabilities();
   }
 
   public function getPolicy($capability) {
     return $this->getMock()->getPolicy($capability);
   }
 
   // really the *mock* controls who can see an image
   public function hasAutomaticCapability($capability, PhabricatorUser $viewer) {
     return $this->getMock()->hasAutomaticCapability($capability, $viewer);
   }
 
 }
diff --git a/src/applications/pholio/storage/PholioMock.php b/src/applications/pholio/storage/PholioMock.php
index 569513cb46..7ce4ece479 100644
--- a/src/applications/pholio/storage/PholioMock.php
+++ b/src/applications/pholio/storage/PholioMock.php
@@ -1,333 +1,334 @@
 <?php
 
 final class PholioMock extends PholioDAO
   implements
     PhabricatorMarkupInterface,
     PhabricatorPolicyInterface,
     PhabricatorSubscribableInterface,
     PhabricatorTokenReceiverInterface,
     PhabricatorFlaggableInterface,
     PhabricatorApplicationTransactionInterface,
     PhabricatorProjectInterface,
     PhabricatorDestructibleInterface,
     PhabricatorSpacesInterface,
     PhabricatorMentionableInterface,
     PhabricatorFulltextInterface,
     PhabricatorFerretInterface {
 
   const MARKUP_FIELD_DESCRIPTION  = 'markup:description';
 
   const STATUS_OPEN = 'open';
   const STATUS_CLOSED = 'closed';
 
   protected $authorPHID;
   protected $viewPolicy;
   protected $editPolicy;
 
   protected $name;
   protected $description;
   protected $coverPHID;
   protected $mailKey;
   protected $status;
   protected $spacePHID;
 
   private $images = self::ATTACHABLE;
   private $allImages = self::ATTACHABLE;
   private $coverFile = self::ATTACHABLE;
   private $tokenCount = self::ATTACHABLE;
 
   public static function initializeNewMock(PhabricatorUser $actor) {
     $app = id(new PhabricatorApplicationQuery())
       ->setViewer($actor)
       ->withClasses(array('PhabricatorPholioApplication'))
       ->executeOne();
 
     $view_policy = $app->getPolicy(PholioDefaultViewCapability::CAPABILITY);
     $edit_policy = $app->getPolicy(PholioDefaultEditCapability::CAPABILITY);
 
     return id(new PholioMock())
       ->setAuthorPHID($actor->getPHID())
       ->attachImages(array())
       ->setStatus(self::STATUS_OPEN)
       ->setViewPolicy($view_policy)
       ->setEditPolicy($edit_policy)
       ->setSpacePHID($actor->getDefaultSpacePHID());
   }
 
   public function getMonogram() {
     return 'M'.$this->getID();
   }
 
   public function getURI() {
     return '/'.$this->getMonogram();
   }
 
   protected function getConfiguration() {
     return array(
       self::CONFIG_AUX_PHID => true,
       self::CONFIG_COLUMN_SCHEMA => array(
         'name' => 'text128',
         'description' => 'text',
         'mailKey' => 'bytes20',
         'status' => 'text12',
       ),
       self::CONFIG_KEY_SCHEMA => array(
         'key_phid' => null,
         'phid' => array(
           'columns' => array('phid'),
           'unique' => true,
         ),
         'authorPHID' => array(
           'columns' => array('authorPHID'),
         ),
       ),
     ) + parent::getConfiguration();
   }
 
   public function generatePHID() {
     return PhabricatorPHID::generateNewPHID('MOCK');
   }
 
   public function save() {
     if (!$this->getMailKey()) {
       $this->setMailKey(Filesystem::readRandomCharacters(20));
     }
     return parent::save();
   }
 
   /**
    * These should be the images currently associated with the Mock.
    */
   public function attachImages(array $images) {
     assert_instances_of($images, 'PholioImage');
     $this->images = $images;
     return $this;
   }
 
   public function getImages() {
     $this->assertAttached($this->images);
     return $this->images;
   }
 
   /**
    * These should be *all* images associated with the Mock. This includes
    * images which have been removed and / or replaced from the Mock.
    */
   public function attachAllImages(array $images) {
     assert_instances_of($images, 'PholioImage');
     $this->allImages = $images;
     return $this;
   }
 
   public function getAllImages() {
     $this->assertAttached($this->images);
     return $this->allImages;
   }
 
   public function attachCoverFile(PhabricatorFile $file) {
     $this->coverFile = $file;
     return $this;
   }
 
   public function getCoverFile() {
     $this->assertAttached($this->coverFile);
     return $this->coverFile;
   }
 
   public function getTokenCount() {
     $this->assertAttached($this->tokenCount);
     return $this->tokenCount;
   }
 
   public function attachTokenCount($count) {
     $this->tokenCount = $count;
     return $this;
   }
 
   public function getImageHistorySet($image_id) {
     $images = $this->getAllImages();
     $images = mpull($images, null, 'getID');
     $selected_image = $images[$image_id];
 
     $replace_map = mpull($images, null, 'getReplacesImagePHID');
     $phid_map = mpull($images, null, 'getPHID');
 
     // find the earliest image
     $image = $selected_image;
     while (isset($phid_map[$image->getReplacesImagePHID()])) {
       $image = $phid_map[$image->getReplacesImagePHID()];
     }
 
     // now build history moving forward
     $history = array($image->getID() => $image);
     while (isset($replace_map[$image->getPHID()])) {
       $image = $replace_map[$image->getPHID()];
       $history[$image->getID()] = $image;
     }
 
     return $history;
   }
 
   public function getStatuses() {
     $options = array();
     $options[self::STATUS_OPEN] = pht('Open');
     $options[self::STATUS_CLOSED] = pht('Closed');
     return $options;
   }
 
   public function isClosed() {
     return ($this->getStatus() == 'closed');
   }
 
 
 /* -(  PhabricatorSubscribableInterface Implementation  )-------------------- */
 
 
   public function isAutomaticallySubscribed($phid) {
     return ($this->authorPHID == $phid);
   }
 
 
 /* -(  PhabricatorPolicyInterface Implementation  )-------------------------- */
 
 
   public function getCapabilities() {
     return array(
       PhabricatorPolicyCapability::CAN_VIEW,
       PhabricatorPolicyCapability::CAN_EDIT,
     );
   }
 
   public function getPolicy($capability) {
     switch ($capability) {
       case PhabricatorPolicyCapability::CAN_VIEW:
         return $this->getViewPolicy();
       case PhabricatorPolicyCapability::CAN_EDIT:
         return $this->getEditPolicy();
     }
   }
 
   public function hasAutomaticCapability($capability, PhabricatorUser $viewer) {
     return ($viewer->getPHID() == $this->getAuthorPHID());
   }
 
   public function describeAutomaticCapability($capability) {
     return pht("A mock's owner can always view and edit it.");
   }
 
 
 /* -(  PhabricatorMarkupInterface  )----------------------------------------- */
 
 
   public function getMarkupFieldKey($field) {
     $content = $this->getMarkupText($field);
     return PhabricatorMarkupEngine::digestRemarkupContent($this, $content);
   }
 
   public function newMarkupEngine($field) {
     return PhabricatorMarkupEngine::newMarkupEngine(array());
   }
 
   public function getMarkupText($field) {
     if ($this->getDescription()) {
       return $this->getDescription();
     }
 
     return null;
   }
 
   public function didMarkupText($field, $output, PhutilMarkupEngine $engine) {
     require_celerity_resource('phabricator-remarkup-css');
     return phutil_tag(
       'div',
       array(
         'class' => 'phabricator-remarkup',
       ),
       $output);
   }
 
   public function shouldUseMarkupCache($field) {
     return (bool)$this->getID();
   }
 
 
 /* -(  PhabricatorApplicationTransactionInterface  )------------------------- */
 
 
   public function getApplicationTransactionEditor() {
     return new PholioMockEditor();
   }
 
   public function getApplicationTransactionObject() {
     return $this;
   }
 
   public function getApplicationTransactionTemplate() {
     return new PholioTransaction();
   }
 
   public function willRenderTimeline(
     PhabricatorApplicationTransactionView $timeline,
     AphrontRequest $request) {
 
     PholioMockQuery::loadImages(
       $request->getUser(),
       array($this),
       $need_inline_comments = true);
     $timeline->setMock($this);
     return $timeline;
   }
 
 /* -(  PhabricatorTokenReceiverInterface  )---------------------------------- */
 
 
   public function getUsersToNotifyOfTokenGiven() {
     return array(
       $this->getAuthorPHID(),
     );
   }
 
 
 /* -(  PhabricatorDestructibleInterface  )----------------------------------- */
 
 
   public function destroyObjectPermanently(
     PhabricatorDestructionEngine $engine) {
 
     $this->openTransaction();
-      $images = id(new PholioImage())->loadAllWhere(
-        'mockID = %d',
-        $this->getID());
+      $images = id(new PholioImageQuery())
+        ->setViewer($engine->getViewer())
+        ->withMockIDs(array($this->getID()))
+        ->execute();
       foreach ($images as $image) {
         $image->delete();
       }
 
       $this->delete();
     $this->saveTransaction();
   }
 
 
 /* -(  PhabricatorSpacesInterface  )----------------------------------------- */
 
 
   public function getSpacePHID() {
     return $this->spacePHID;
   }
 
 
 /* -(  PhabricatorFulltextInterface  )--------------------------------------- */
 
 
   public function newFulltextEngine() {
     return new PholioMockFulltextEngine();
   }
 
 
 /* -(  PhabricatorFerretInterface  )----------------------------------------- */
 
   public function newFerretEngine() {
     return new PholioMockFerretEngine();
   }
 
 
 }