/** * {@inheritdoc} */ public function formatImages(Model\Images $model) { $images = $model->getImages(); $data = array(); // Fields to display if ($fields = $model->getFields()) { $fields = array_fill_keys($fields, 1); } foreach ($images as $image) { $entry = array('added' => $this->dateFormatter->formatDate($image->getAddedDate()), 'updated' => $this->dateFormatter->formatDate($image->getUpdatedDate()), 'checksum' => $image->getChecksum(), 'originalChecksum' => $image->getOriginalChecksum(), 'extension' => $image->getExtension(), 'size' => $image->getFilesize(), 'width' => $image->getWidth(), 'height' => $image->getHeight(), 'mime' => $image->getMimeType(), 'imageIdentifier' => $image->getImageIdentifier(), 'publicKey' => $image->getPublicKey()); // Add metadata if the field is to be displayed if (empty($fields) || isset($fields['metadata'])) { $metadata = $image->getMetadata(); if (is_array($metadata)) { if (empty($metadata)) { $metadata = new stdClass(); } $entry['metadata'] = $metadata; } } // Remove elements that should not be displayed if (!empty($fields)) { foreach (array_keys($entry) as $key) { if (!isset($fields[$key])) { unset($entry[$key]); } } } $data[] = $entry; } return $this->encode(array('search' => array('hits' => $model->getHits(), 'page' => $model->getPage(), 'limit' => $model->getLimit(), 'count' => $model->getCount()), 'images' => $data)); }
/** * @covers Imbo\Model\Images::getCount */ public function testCanCountImages() { $this->assertSame(0, $this->model->getCount()); $images = array($this->getMock('Imbo\\Model\\Image'), $this->getMock('Imbo\\Model\\Image'), $this->getMock('Imbo\\Model\\Image')); $this->model->setImages($images); $this->assertSame(3, $this->model->getCount()); }
/** * @covers Imbo\Model\Images::getData */ public function testGetData() { $images = [$this->getMock('Imbo\\Model\\Image'), $this->getMock('Imbo\\Model\\Image'), $this->getMock('Imbo\\Model\\Image')]; $fields = ['width', 'height']; $this->model->setImages($images)->setFields($fields)->setHits(10)->setLimit(11)->setPage(12); $this->assertSame(['images' => $images, 'fields' => $fields, 'count' => 3, 'hits' => 10, 'limit' => 11, 'page' => 12], $this->model->getData()); }
/** * Load images * * @param EventInterface $event An event instance */ public function loadImages(EventInterface $event) { $query = $this->getImagesQuery(); $params = $event->getRequest()->query; $returnMetadata = false; if ($params->has('page')) { $query->page($params->get('page')); } if ($params->has('limit')) { $query->limit($params->get('limit')); } if ($params->has('metadata')) { $query->returnMetadata($params->get('metadata')); $returnMetadata = true; } if ($params->has('from')) { $query->from($params->get('from')); } if ($params->has('to')) { $query->to($params->get('to')); } if ($params->has('sort')) { $sort = $params->get('sort'); if (is_array($sort)) { $query->sort($sort); } } if ($params->has('ids')) { $ids = $params->get('ids'); if (is_array($ids)) { $query->imageIdentifiers($ids); } } if ($params->has('checksums')) { $checksums = $params->get('checksums'); if (is_array($checksums)) { $query->checksums($checksums); } } if ($params->has('originalChecksums')) { $checksums = $params->get('originalChecksums'); if (is_array($checksums)) { $query->originalChecksums($checksums); } } $publicKey = $event->getRequest()->getPublicKey(); $response = $event->getResponse(); $database = $event->getDatabase(); // Create the model and set some pagination values $model = new Model\Images(); $model->setLimit($query->limit())->setPage($query->page()); $images = $database->getImages($publicKey, $query, $model); $modelImages = array(); foreach ($images as $image) { $entry = new Model\Image(); $entry->setFilesize($image['size'])->setWidth($image['width'])->setHeight($image['height'])->setPublicKey($publicKey)->setImageIdentifier($image['imageIdentifier'])->setChecksum($image['checksum'])->setOriginalChecksum(isset($image['originalChecksum']) ? $image['originalChecksum'] : null)->setMimeType($image['mime'])->setExtension($image['extension'])->setAddedDate($image['added'])->setUpdatedDate($image['updated']); if ($returnMetadata) { $entry->setMetadata($image['metadata']); } $modelImages[] = $entry; } // Add images to the model $model->setImages($modelImages); if ($params->has('fields')) { $fields = $params->get('fields'); if (is_array($fields)) { $model->setFields($fields); } } $lastModified = $database->getLastModified($publicKey); $response->setModel($model)->setLastModified($lastModified); }
/** * {@inheritdoc} */ public function getImages($publicKey, Query $query, Images $model) { $images = array(); $qb = $this->getConnection()->createQueryBuilder(); $qb->select('*')->from($this->tableNames['imageinfo'], 'i')->where('i.publicKey = :publicKey')->setParameter(':publicKey', $publicKey); if ($sort = $query->sort()) { // Fields valid for sorting $validFields = array('size' => true, 'publicKey' => true, 'imageIdentifier' => true, 'extension' => true, 'mime' => true, 'added' => true, 'updated' => true, 'width' => true, 'height' => true, 'checksum' => true, 'originalChecksum' => true); foreach ($sort as $f) { if (!isset($validFields[$f['field']])) { throw new InvalidArgumentException('Invalid sort field: ' . $f['field'], 400); } $qb->addOrderBy($f['field'], $f['sort']); } } else { $qb->orderBy('added', 'DESC'); } $from = $query->from(); $to = $query->to(); if ($from || $to) { if ($from !== null) { $qb->andWhere('added >= :from')->setParameter(':from', $from); } if ($to !== null) { $qb->andWhere('added <= :to')->setParameter(':to', $to); } } if ($imageIdentifiers = $query->imageIdentifiers()) { $expr = $qb->expr(); $composite = $expr->orX(); foreach ($imageIdentifiers as $i => $id) { $composite->add($expr->eq('i.imageIdentifier', ':imageIdentifier' . $i)); $qb->setParameter(':imageIdentifier' . $i, $id); } $qb->andWhere($composite); } if ($checksums = $query->checksums()) { $expr = $qb->expr(); $composite = $expr->orX(); foreach ($checksums as $i => $id) { $composite->add($expr->eq('i.checksum', ':checksum' . $i)); $qb->setParameter(':checksum' . $i, $id); } $qb->andWhere($composite); } if ($originalChecksums = $query->originalChecksums()) { $expr = $qb->expr(); $composite = $expr->orX(); foreach ($originalChecksums as $i => $id) { $composite->add($expr->eq('i.originalChecksum', ':originalChecksum' . $i)); $qb->setParameter(':originalChecksum' . $i, $id); } $qb->andWhere($composite); } // Create a querybuilder that will be used to fetch the hits number, and update the model $hitsQb = clone $qb; $hitsQb->select('COUNT(i.id)'); $stmt = $hitsQb->execute(); $model->setHits((int) $stmt->fetchColumn()); if ($limit = $query->limit()) { $qb->setMaxResults($limit); } if ($page = $query->page()) { $offset = (int) $query->limit() * ($page - 1); $qb->setFirstResult($offset); } $stmt = $qb->execute(); $rows = $stmt->fetchAll(PDO::FETCH_ASSOC); $returnMetadata = $query->returnMetadata(); foreach ($rows as $row) { $image = array('extension' => $row['extension'], 'added' => new DateTime('@' . $row['added'], new DateTimeZone('UTC')), 'updated' => new DateTime('@' . $row['updated'], new DateTimeZone('UTC')), 'checksum' => $row['checksum'], 'originalChecksum' => isset($row['originalChecksum']) ? $row['originalChecksum'] : null, 'publicKey' => $row['publicKey'], 'imageIdentifier' => $row['imageIdentifier'], 'mime' => $row['mime'], 'size' => (int) $row['size'], 'width' => (int) $row['width'], 'height' => (int) $row['height']); if ($returnMetadata) { $image['metadata'] = $this->getMetadata($publicKey, $row['imageIdentifier']); } $images[] = $image; } return $images; }
/** * Handle metadata search operation * * page => Page number. Defaults to 1 * limit => Limit to a number of images pr. page. Defaults to 20 * metadata => Whether or not to include metadata pr. image. Set to 1 to enable * query => urlencoded json data to use in the query * from => Unix timestamp to fetch from * to => Unit timestamp to fetch to * * @param Imbo\EventListener\ListenerInterface $event The current event * @param array $users Array with image identifiers */ protected function searchHandler(EventInterface $event, array $users) { $request = $event->getRequest(); $params = $request->query; // Extract query $metadataQuery = $request->getContent(); // If no metadata is provided, we'll let db.images.load take over if (!$metadataQuery) { $event->getManager()->trigger('db.images.load'); return; } // Check access token $event->getManager()->trigger('auth.accesstoken'); // Check that the public key has access to the users $this->validateAccess($event, $users); // Build query params array $queryParams = ['page' => $params->get('page', 1), 'limit' => $params->get('limit', 20), 'from' => $params->get('from'), 'to' => $params->get('to'), 'sort' => $this->getSortParams($event)]; if ($queryParams['page'] < 1) { throw new RuntimeException('Invalid param. "page" must be a positive number.', 400); } if ($queryParams['limit'] < 1) { throw new RuntimeException('Invalid param. "limit" must be a positive number.', 400); } // Parse the query JSON and transform it to an AST $ast = DslParser::parse($metadataQuery); // Query backend using the AST $backendResponse = $this->backend->search($users, $ast, $queryParams); // If we didn't get hits in the search backend, prepare a response if (!$backendResponse->getImageIdentifiers()) { // Create the model and set some pagination values $model = new ImagesModel(); $model->setLimit($queryParams['limit'])->setPage($queryParams['page'])->setHits($backendResponse->getHits()); $response = $event->getResponse(); $response->setModel($model); return; } $imageIdentifiers = $backendResponse->getImageIdentifiers(); // Set the ids to fetch from the Imbo backend $params->set('ids', $imageIdentifiers); // In order to paginate the already paginated resultset, we'll // set the page param to 0 before triggering db.images.load $params->set('page', 0); // Unset date range parameters $params->remove('to'); $params->remove('from'); // Trigger image loading from imbo DB $event->getManager()->trigger('db.images.load'); $responseModel = $event->getResponse()->getModel(); // Set the actual page used for querying search backend on the response $responseModel->setPage($queryParams['page']); $responseModel->setHits($backendResponse->getHits()); // Sort the response image so they match the order of identifiers // returned from search backend $this->sortSearchResponse($responseModel, $imageIdentifiers); }
/** * {@inheritdoc} */ public function getImages($publicKey, Query $query, Images $model) { // Initialize return value $images = []; // Query data $queryData = ['publicKey' => $publicKey]; $from = $query->from(); $to = $query->to(); if ($from || $to) { $tmp = []; if ($from !== null) { $tmp['$gte'] = $from; } if ($to !== null) { $tmp['$lte'] = $to; } $queryData['added'] = $tmp; } $imageIdentifiers = $query->imageIdentifiers(); if (!empty($imageIdentifiers)) { $queryData['imageIdentifier']['$in'] = $imageIdentifiers; } $checksums = $query->checksums(); if (!empty($checksums)) { $queryData['checksum']['$in'] = $checksums; } $originalChecksums = $query->originalChecksums(); if (!empty($originalChecksums)) { $queryData['originalChecksum']['$in'] = $originalChecksums; } // Sorting $sort = ['added' => -1]; if ($querySort = $query->sort()) { $sort = []; foreach ($querySort as $s) { $sort[$s['field']] = $s['sort'] === 'asc' ? 1 : -1; } } // Fields to fetch $fields = array_fill_keys(['extension', 'added', 'checksum', 'originalChecksum', 'updated', 'publicKey', 'imageIdentifier', 'mime', 'size', 'width', 'height'], true); if ($query->returnMetadata()) { $fields['metadata'] = true; } try { $cursor = $this->getImageCollection()->find($queryData, $fields)->limit($query->limit())->sort($sort); // Skip some images if a page has been set if (($page = $query->page()) > 1) { $skip = $query->limit() * ($page - 1); $cursor->skip($skip); } foreach ($cursor as $image) { unset($image['_id']); $image['added'] = new DateTime('@' . $image['added'], new DateTimeZone('UTC')); $image['updated'] = new DateTime('@' . $image['updated'], new DateTimeZone('UTC')); $images[] = $image; } // Update model $model->setHits($cursor->count()); } catch (MongoException $e) { throw new DatabaseException('Unable to search for images', 500, $e); } return $images; }
/** * {@inheritdoc} */ public function formatImages(Model\Images $model) { $images = ''; if ($fields = $model->getFields()) { $fields = array_fill_keys($fields, 1); } foreach ($model->getImages() as $image) { $images .= '<image>'; if (empty($fields) || isset($fields['publicKey'])) { $images .= '<publicKey>' . $image->getPublicKey() . '</publicKey>'; } if (empty($fields) || isset($fields['imageIdentifier'])) { $images .= '<imageIdentifier>' . $image->getImageIdentifier() . '</imageIdentifier>'; } if (empty($fields) || isset($fields['checksum'])) { $images .= '<checksum>' . $image->getChecksum() . '</checksum>'; } if (empty($fields) || isset($fields['originalChecksum'])) { $images .= '<originalChecksum>' . $image->getOriginalChecksum() . '</originalChecksum>'; } if (empty($fields) || isset($fields['mime'])) { $images .= '<mime>' . $image->getMimeType() . '</mime>'; } if (empty($fields) || isset($fields['extension'])) { $images .= '<extension>' . $image->getExtension() . '</extension>'; } if (empty($fields) || isset($fields['added'])) { $images .= '<added>' . $this->dateFormatter->formatDate($image->getAddedDate()) . '</added>'; } if (empty($fields) || isset($fields['updated'])) { $images .= '<updated>' . $this->dateFormatter->formatDate($image->getUpdatedDate()) . '</updated>'; } if (empty($fields) || isset($fields['size'])) { $images .= '<size>' . $image->getFilesize() . '</size>'; } if (empty($fields) || isset($fields['width'])) { $images .= '<width>' . $image->getWidth() . '</width>'; } if (empty($fields) || isset($fields['height'])) { $images .= '<height>' . $image->getHeight() . '</height>'; } $metadata = $image->getMetadata(); if (is_array($metadata) && (empty($fields) || isset($fields['metadata']))) { $images .= '<metadata>'; foreach ($metadata as $key => $value) { $images .= '<tag key="' . $key . '">' . $value . '</tag>'; } $images .= '</metadata>'; } $images .= '</image>'; } return <<<IMAGES <?xml version="1.0" encoding="UTF-8"?> <imbo> <search> <hits>{$model->getHits()}</hits> <page>{$model->getPage()}</page> <limit>{$model->getLimit()}</limit> <count>{$model->getCount()}</count> </search> <images>{$images}</images> </imbo> IMAGES; }