public function buildConduitResponse(ConduitAPIRequest $request, ConduitAPIMethod $method)
 {
     $viewer = $this->requireViewer();
     $query_key = $request->getValue('queryKey');
     if (!strlen($query_key)) {
         $saved_query = new PhabricatorSavedQuery();
     } else {
         if ($this->isBuiltinQuery($query_key)) {
             $saved_query = $this->buildSavedQueryFromBuiltin($query_key);
         } else {
             $saved_query = id(new PhabricatorSavedQueryQuery())->setViewer($viewer)->withQueryKeys(array($query_key))->executeOne();
             if (!$saved_query) {
                 throw new Exception(pht('Query key "%s" does not correspond to a valid query.', $query_key));
             }
         }
     }
     $constraints = $request->getValue('constraints', array());
     $fields = $this->getSearchFieldsForConduit();
     foreach ($fields as $key => $field) {
         if (!$field->getConduitParameterType()) {
             unset($fields[$key]);
         }
     }
     $valid_constraints = array();
     foreach ($fields as $field) {
         foreach ($field->getValidConstraintKeys() as $key) {
             $valid_constraints[$key] = true;
         }
     }
     foreach ($constraints as $key => $constraint) {
         if (empty($valid_constraints[$key])) {
             throw new Exception(pht('Constraint "%s" is not a valid constraint for this query.', $key));
         }
     }
     foreach ($fields as $field) {
         if (!$field->getValueExistsInConduitRequest($constraints)) {
             continue;
         }
         $value = $field->readValueFromConduitRequest($constraints, $request->getIsStrictlyTyped());
         $saved_query->setParameter($field->getKey(), $value);
     }
     // NOTE: Currently, when running an ad-hoc query we never persist it into
     // a saved query. We might want to add an option to do this in the future
     // (for example, to enable a CLI-to-Web workflow where user can view more
     // details about results by following a link), but have no use cases for
     // it today. If we do identify a use case, we could save the query here.
     $query = $this->buildQueryFromSavedQuery($saved_query);
     $pager = $this->newPagerForSavedQuery($saved_query);
     $attachments = $this->getConduitSearchAttachments();
     // TODO: Validate this better.
     $attachment_specs = $request->getValue('attachments', array());
     $attachments = array_select_keys($attachments, array_keys($attachment_specs));
     foreach ($attachments as $key => $attachment) {
         $attachment->setViewer($viewer);
     }
     foreach ($attachments as $key => $attachment) {
         $attachment->willLoadAttachmentData($query, $attachment_specs[$key]);
     }
     $this->setQueryOrderForConduit($query, $request);
     $this->setPagerLimitForConduit($pager, $request);
     $this->setPagerOffsetsForConduit($pager, $request);
     $objects = $this->executeQuery($query, $pager);
     $data = array();
     if ($objects) {
         $field_extensions = $this->getConduitFieldExtensions();
         $extension_data = array();
         foreach ($field_extensions as $key => $extension) {
             $extension_data[$key] = $extension->loadExtensionConduitData($objects);
         }
         $attachment_data = array();
         foreach ($attachments as $key => $attachment) {
             $attachment_data[$key] = $attachment->loadAttachmentData($objects, $attachment_specs[$key]);
         }
         foreach ($objects as $object) {
             $field_map = $this->getObjectWireFieldsForConduit($object, $field_extensions, $extension_data);
             $attachment_map = array();
             foreach ($attachments as $key => $attachment) {
                 $attachment_map[$key] = $attachment->getAttachmentForObject($object, $attachment_data[$key], $attachment_specs[$key]);
             }
             // If this is empty, we still want to emit a JSON object, not a
             // JSON list.
             if (!$attachment_map) {
                 $attachment_map = (object) $attachment_map;
             }
             $id = (int) $object->getID();
             $phid = $object->getPHID();
             $data[] = array('id' => $id, 'type' => phid_get_type($phid), 'phid' => $phid, 'fields' => $field_map, 'attachments' => $attachment_map);
         }
     }
     return array('data' => $data, 'maps' => $method->getQueryMaps($query), 'query' => array('queryKey' => $saved_query->getQueryKey()), 'cursor' => array('limit' => $pager->getPageSize(), 'after' => $pager->getNextPageID(), 'before' => $pager->getPrevPageID(), 'order' => $request->getValue('order')));
 }
 public function buildConduitResponse(ConduitAPIRequest $request, ConduitAPIMethod $method)
 {
     $viewer = $this->requireViewer();
     $query_key = $request->getValue('queryKey');
     if (!strlen($query_key)) {
         $saved_query = new PhabricatorSavedQuery();
     } else {
         if ($this->isBuiltinQuery($query_key)) {
             $saved_query = $this->buildSavedQueryFromBuiltin($query_key);
         } else {
             $saved_query = id(new PhabricatorSavedQueryQuery())->setViewer($viewer)->withQueryKeys(array($query_key))->executeOne();
             if (!$saved_query) {
                 throw new Exception(pht('Query key "%s" does not correspond to a valid query.', $query_key));
             }
         }
     }
     $constraints = $request->getValue('constraints', array());
     $fields = $this->getSearchFieldsForConduit();
     foreach ($fields as $key => $field) {
         if (!$field->getConduitParameterType()) {
             unset($fields[$key]);
         }
     }
     foreach ($fields as $field) {
         if (!$field->getValueExistsInConduitRequest($constraints)) {
             continue;
         }
         $value = $field->readValueFromConduitRequest($constraints);
         $saved_query->setParameter($field->getKey(), $value);
     }
     $this->saveQuery($saved_query);
     $query = $this->buildQueryFromSavedQuery($saved_query);
     $pager = $this->newPagerForSavedQuery($saved_query);
     $attachments = $this->getConduitSearchAttachments();
     // TODO: Validate this better.
     $attachment_specs = $request->getValue('attachments', array());
     $attachments = array_select_keys($attachments, array_keys($attachment_specs));
     foreach ($attachments as $key => $attachment) {
         $attachment->setViewer($viewer);
     }
     foreach ($attachments as $key => $attachment) {
         $attachment->willLoadAttachmentData($query, $attachment_specs[$key]);
     }
     $this->setQueryOrderForConduit($query, $request);
     $this->setPagerLimitForConduit($pager, $request);
     $this->setPagerOffsetsForConduit($pager, $request);
     $objects = $this->executeQuery($query, $pager);
     $data = array();
     if ($objects) {
         $field_extensions = $this->getConduitFieldExtensions();
         $attachment_data = array();
         foreach ($attachments as $key => $attachment) {
             $attachment_data[$key] = $attachment->loadAttachmentData($objects, $attachment_specs[$key]);
         }
         foreach ($objects as $object) {
             $field_map = $this->getObjectWireFieldsForConduit($object, $field_extensions);
             $attachment_map = array();
             foreach ($attachments as $key => $attachment) {
                 $attachment_map[$key] = $attachment->getAttachmentForObject($object, $attachment_data[$key], $attachment_specs[$key]);
             }
             // If this is empty, we still want to emit a JSON object, not a
             // JSON list.
             if (!$attachment_map) {
                 $attachment_map = (object) $attachment_map;
             }
             $id = (int) $object->getID();
             $phid = $object->getPHID();
             $data[] = array('id' => $id, 'type' => phid_get_type($phid), 'phid' => $phid, 'fields' => $field_map, 'attachments' => $attachment_map);
         }
     }
     return array('data' => $data, 'maps' => $method->getQueryMaps($query), 'query' => array('queryKey' => $saved_query->getQueryKey()), 'cursor' => array('limit' => $pager->getPageSize(), 'after' => $pager->getNextPageID(), 'before' => $pager->getPrevPageID(), 'order' => $request->getValue('order')));
 }