diff --git a/README.md b/README.md index 9c14ee9..06c6187 100644 --- a/README.md +++ b/README.md @@ -171,13 +171,13 @@ Then, you can send the request using the `Rekognition` facade `detectLabels` met $response = Rekognition::detectLabels($detectLabelsData); ``` -Response will be an instance of [`ResultData`](src/Data/ResultData/ResultData.php) object. +Response will be an instance of [`DetectLabelsResultData`](src/Data/ResultData/DetectLabelsResultData.php) object.
-This is the sample ResultData: +This is the sample DetectLabelsResultData: ```php -ResultData( +DetectLabelsResultData( labels: DataCollection([ LabelData( name: 'Adult', diff --git a/src/Data/Contracts/RekognitionDataFormatInterface.php b/src/Data/Contracts/RekognitionDataFormatInterface.php new file mode 100644 index 0000000..cd7961e --- /dev/null +++ b/src/Data/Contracts/RekognitionDataFormatInterface.php @@ -0,0 +1,21 @@ + $this->collectionId, + 'Tags' => $this->tags, + ], + fn ($value) => $value !== null + ); + } +} \ No newline at end of file diff --git a/src/Data/DeleteCollectionData.php b/src/Data/DeleteCollectionData.php new file mode 100644 index 0000000..d4c74c9 --- /dev/null +++ b/src/Data/DeleteCollectionData.php @@ -0,0 +1,36 @@ + $this->collectionId, + ]; + } +} \ No newline at end of file diff --git a/src/Data/DetectLabelsData.php b/src/Data/DetectLabelsData.php index 0f2d3b6..31b11df 100644 --- a/src/Data/DetectLabelsData.php +++ b/src/Data/DetectLabelsData.php @@ -4,6 +4,7 @@ namespace MoeMizrak\Rekognition\Data; +use MoeMizrak\Rekognition\Data\Contracts\RekognitionDataFormatInterface; use Spatie\LaravelData\Data; /** @@ -12,7 +13,7 @@ * * @class DetectLabelsData */ -final class DetectLabelsData extends Data +final class DetectLabelsData extends Data implements RekognitionDataFormatInterface { public function __construct( /* @@ -58,9 +59,7 @@ public function __construct( ) {} /** - * Convert the data to an AWS Rekognition array format, excluding null values. - * - * @return array + * @inheritDoc */ public function toRekognitionDataFormat(): array { diff --git a/src/Data/DetectLabelsImagePropertiesSettingsData.php b/src/Data/DetectLabelsImagePropertiesSettingsData.php index c636574..663d392 100644 --- a/src/Data/DetectLabelsImagePropertiesSettingsData.php +++ b/src/Data/DetectLabelsImagePropertiesSettingsData.php @@ -4,6 +4,7 @@ namespace MoeMizrak\Rekognition\Data; +use MoeMizrak\Rekognition\Data\Contracts\RekognitionDataFormatInterface; use Spatie\LaravelData\Data; /** @@ -12,7 +13,7 @@ * * @class DetectLabelsImagePropertiesSettingsData */ -final class DetectLabelsImagePropertiesSettingsData extends Data +final class DetectLabelsImagePropertiesSettingsData extends Data implements RekognitionDataFormatInterface { public function __construct( /* @@ -25,9 +26,7 @@ public function __construct( ) {} /** - * Convert the data to an AWS Rekognition array format. - * - * @return array + * @inheritDoc */ public function toRekognitionDataFormat(): array { diff --git a/src/Data/GeneralLabelsSettingsData.php b/src/Data/GeneralLabelsSettingsData.php index 07489b5..8a66bdf 100644 --- a/src/Data/GeneralLabelsSettingsData.php +++ b/src/Data/GeneralLabelsSettingsData.php @@ -4,6 +4,7 @@ namespace MoeMizrak\Rekognition\Data; +use MoeMizrak\Rekognition\Data\Contracts\RekognitionDataFormatInterface; use Spatie\LaravelData\Data; /** @@ -13,7 +14,7 @@ * * @class GeneralLabelsSettingsData */ -final class GeneralLabelsSettingsData extends Data +final class GeneralLabelsSettingsData extends Data implements RekognitionDataFormatInterface { public function __construct( /* @@ -46,9 +47,7 @@ public function __construct( ) {} /** - * Convert the data to an AWS Rekognition array format. - * - * @return array + * @inheritDoc */ public function toRekognitionDataFormat(): array { diff --git a/src/Data/ImageData.php b/src/Data/ImageData.php index aba688b..d6d0a25 100644 --- a/src/Data/ImageData.php +++ b/src/Data/ImageData.php @@ -4,6 +4,7 @@ namespace MoeMizrak\Rekognition\Data; +use MoeMizrak\Rekognition\Data\Contracts\RekognitionDataFormatInterface; use Spatie\LaravelData\Data; /** @@ -13,7 +14,7 @@ * * @class ImageData */ -final class ImageData extends Data +final class ImageData extends Data implements RekognitionDataFormatInterface { public function __construct( /* @@ -32,9 +33,7 @@ public function __construct( ) {} /** - * Convert the data to an AWS Rekognition array format. - * - * @return array + * @inheritDoc */ public function toRekognitionDataFormat(): array { diff --git a/src/Data/ListCollectionsData.php b/src/Data/ListCollectionsData.php new file mode 100644 index 0000000..bbf6b39 --- /dev/null +++ b/src/Data/ListCollectionsData.php @@ -0,0 +1,47 @@ + $this->maxResults, + 'NextToken' => $this->nextToken, + ], + fn ($value) => $value !== null + ); + } +} \ No newline at end of file diff --git a/src/Data/ResultData/CreateCollectionResultData.php b/src/Data/ResultData/CreateCollectionResultData.php new file mode 100644 index 0000000..25cc473 --- /dev/null +++ b/src/Data/ResultData/CreateCollectionResultData.php @@ -0,0 +1,46 @@ +retrieveMetaData($response), + ); + } + + /** + * Forms the Rekognition deleteCollection response to DeleteCollectionResultData including status code and metadata. + * + * @param array $response + * + * @return DeleteCollectionResultData + */ + public function formDeleteCollectionResponse(array $response): DeleteCollectionResultData + { + return new DeleteCollectionResultData( + statusCode: Arr::get($response, 'StatusCode'), + metadata : $this->retrieveMetaData($response), + ); + } + + /** + * Forms the Rekognition createCollection response to CreateCollectionResultData including collection arn, face model version, status code, and metadata. + * + * @param array $response + * + * @return CreateCollectionResultData + */ + public function formCreateCollectionResponse(array $response): CreateCollectionResultData + { + return new CreateCollectionResultData( + collectionArn : Arr::get($response, 'CollectionArn'), + faceModelVersion: Arr::get($response, 'FaceModelVersion'), + statusCode : Arr::get($response, 'StatusCode'), + metadata : $this->retrieveMetaData($response), + ); + } + + /** + * Forms the Rekognition detect labels response to DetectLabelsResultData including labels, label model version, orientation correction, image properties, and metadata. + * + * @param array $response + * + * @return DetectLabelsResultData + */ + public function formDetectLabelsResponse(array $response): DetectLabelsResultData + { + return new DetectLabelsResultData( + labels : $this->retrieveLabels($response), + labelModelVersion : Arr::get($response, 'LabelModelVersion'), + orientationCorrection: Arr::get($response, 'OrientationCorrection'), + imageProperties : $this->retrieveImageProperties($response), + metadata : $this->retrieveMetaData($response), + ); + } + + /** + * Retrieves the metadata of the response including status code, effective uri, headers, and transfer stats. + * + * @param array $response + * + * @return MetaData + */ + private function retrieveMetaData(array $response): MetaData + { + return new MetaData( + statusCode : Arr::get($response, '@metadata.statusCode'), + effectiveUri : Arr::get($response, '@metadata.effectiveUri'), + headers : Arr::get($response, '@metadata.headers'), + transferStats : Arr::get($response, '@metadata.transferStats'), + ); + } + + /** + * Retrieves the image properties of the response including background, dominant colors, foreground, and quality. + * + * @param array $response + * + * @return ImagePropertiesData + */ + private function retrieveImageProperties(array $response): ImagePropertiesData + { + $dominantColors = []; + $returnedImageProperties = Arr::get($response, 'ImageProperties', []); + $returnedDominantColors = Arr::get($returnedImageProperties, 'DominantColors', []); + + // Map the dominant colors data and add them to the dominant colors array. + foreach ($returnedDominantColors as $returnedDominantColor) { + $returnedDominantColor = new DominantColorsData( + blue : Arr::get($returnedDominantColor, 'Blue'), + cssColor : Arr::get($returnedDominantColor, 'CSSColor'), + green : Arr::get($returnedDominantColor, 'Green'), + hexCode : Arr::get($returnedDominantColor, 'HexCode'), + pixelPercent : Arr::get($returnedDominantColor, 'PixelPercent'), + red : Arr::get($returnedDominantColor, 'Red'), + simplifiedColor: Arr::get($returnedDominantColor, 'SimplifiedColor'), + ); + + $dominantColors[] = $returnedDominantColor; + } + + $returnedQuality = Arr::get($returnedImageProperties, 'Quality'); + + $quality = new QualityData( + brightness: Arr::get($returnedQuality, 'Brightness'), + contrast : Arr::get($returnedQuality, 'Contrast'), + sharpness : Arr::get($returnedQuality, 'Sharpness'), + ); + + return new ImagePropertiesData( + background : $this->retrieveBackgroundImageProperty($returnedImageProperties), + dominantColors: new DataCollection(DominantColorsData::class, $dominantColors), + foreground : $this->retrieveForegroundImageProperty($returnedImageProperties), + quality : $quality, + ); + } + + /** + * Retrieves the foreground image property including dominant colors and quality. + * + * @param array|null $returnedImageProperties + * + * @return ForegroundData + */ + private function retrieveForegroundImageProperty(?array $returnedImageProperties): ForegroundData + { + $returnedForeground = Arr::get($returnedImageProperties, 'Foreground'); + $returnedForegroundDominantColors = Arr::get($returnedForeground, 'DominantColors'); + $returnedQuality = Arr::get($returnedForeground, 'Quality'); + + return new ForegroundData( + dominantColors: $this->mapDominantColors($returnedForegroundDominantColors), + quality : $this->mapQualityData($returnedQuality), + ); + } + + /** + * Retrieves the background image property including dominant colors and quality. + * + * @param array|null $returnedImageProperties + * + * @return BackgroundData + */ + private function retrieveBackgroundImageProperty(?array $returnedImageProperties): BackgroundData + { + $returnedBackground = Arr::get($returnedImageProperties, 'Background'); + $returnedBackgroundDominantColors = Arr::get($returnedBackground, 'DominantColors'); + $returnedQuality = Arr::get($returnedBackground, 'Quality'); + + return new BackgroundData( + dominantColors: $this->mapDominantColors($returnedBackgroundDominantColors), + quality : $this->mapQualityData($returnedQuality), + ); + } + + /** + * Maps the dominant colors data and returns a DataCollection of DominantColorsData. + * + * @param array|null $returnedColors + * + * @return DataCollection + */ + private function mapDominantColors(?array $returnedColors): DataCollection + { + $dominantColors = array_map(function ($color) { + return new DominantColorsData( + blue : Arr::get($color, 'Blue'), + cssColor : Arr::get($color, 'CSSColor'), + green : Arr::get($color, 'Green'), + hexCode : Arr::get($color, 'HexCode'), + pixelPercent : Arr::get($color, 'PixelPercent'), + red : Arr::get($color, 'Red'), + simplifiedColor: Arr::get($color, 'SimplifiedColor'), + ); + }, $returnedColors ?? []); + + return new DataCollection(DominantColorsData::class, $dominantColors); + } + + /** + * Maps the quality data and returns a QualityData object. + * + * @param array|null $returnedQuality + * + * @return QualityData + */ + private function mapQualityData(?array $returnedQuality): QualityData + { + return new QualityData( + brightness: Arr::get($returnedQuality, 'Brightness'), + contrast : Arr::get($returnedQuality, 'Contrast'), + sharpness : Arr::get($returnedQuality, 'Sharpness'), + ); + } + + /** + * Retrieves the labels of the response including name, confidence, instances, parents, aliases, and categories. + * + * @param array $response + * + * @return DataCollection + */ + private function retrieveLabels(array $response): DataCollection + { + $labels = []; + $returnedLabels = Arr::get($response, 'Labels', []); + + // Loop through the returned labels and map them accordingly. + foreach ($returnedLabels as $returnedLabel) { + $instances = []; + $name = Arr::get($returnedLabel, 'Name'); + $confidence = Arr::get($returnedLabel, 'Confidence'); + $returnedInstances = Arr::get($returnedLabel, 'Instances', []); + + // Loop through the returned instances of the returned label and map them accordingly and add them to the instances array. + foreach ($returnedInstances as $returnedInstance) { + $returnedBoundingBox = Arr::get($returnedInstance, 'BoundingBox'); + $returnedConfidence = Arr::get($returnedInstance, 'Confidence'); + + $boundingBox = new BoundingBoxData( + height: Arr::get($returnedBoundingBox, 'Height'), + left : Arr::get($returnedBoundingBox, 'Left'), + top : Arr::get($returnedBoundingBox, 'Top'), + width : Arr::get($returnedBoundingBox, 'Width'), + ); + + $instance = new InstanceData( + boundingBox: $boundingBox, + confidence : $returnedConfidence, + ); + + $instances[] = $instance; + } + + $parents = []; + $returnedParents = Arr::get($returnedLabel, 'Parents', []); + + // Loop through the returned parents and map them accordingly, and add them to the parents array. + foreach ($returnedParents as $returnedParent) { + $parent = new ParentData( + name: Arr::get($returnedParent, 'Name'), + ); + + $parents[] = $parent; + } + + $aliases = []; + $returnedAliases = Arr::get($returnedLabel, 'Aliases', []); + + foreach ($returnedAliases as $returnedAlias) { + $aliasesItem = new AliasData( + name: Arr::get($returnedAlias, 'Name'), + ); + + $aliases[] = $aliasesItem; + } + + $categories = []; + $returnedCategories = Arr::get($returnedLabel, 'Categories', []); + + foreach ($returnedCategories as $returnedCategory) { + $category = new CategoryData( + name: Arr::get($returnedCategory, 'Name'), + ); + + $categories[] = $category; + } + + $label = new LabelData( + aliases : new DataCollection(AliasData::class, $aliases), + categories: new DataCollection(CategoryData::class, $categories), + confidence: $confidence, + instances : new DataCollection(InstanceData::class, $instances), + name : $name, + parents : new DataCollection(ParentData::class, $parents), + ); + + $labels[] = $label; + } + + return new DataCollection(LabelData::class, $labels); + } +} \ No newline at end of file diff --git a/src/RekognitionAPI.php b/src/RekognitionAPI.php index 839ace3..ab9e5a9 100644 --- a/src/RekognitionAPI.php +++ b/src/RekognitionAPI.php @@ -5,6 +5,7 @@ namespace MoeMizrak\Rekognition; use Aws\Rekognition\RekognitionClient; +use MoeMizrak\Rekognition\Helpers\RekognitionHelper; /** * RekognitionAPI abstract class responsible for encapsulating the RekognitionRequest class. @@ -17,6 +18,10 @@ * RekognitionAPI constructor. * * @param RekognitionClient $client + * @param RekognitionHelper $rekognitionHelper */ - public function __construct(protected RekognitionClient $client) {} + public function __construct( + protected RekognitionClient $client, + protected RekognitionHelper $rekognitionHelper, + ) {} } \ No newline at end of file diff --git a/src/RekognitionRequest.php b/src/RekognitionRequest.php index 34bae16..fbc19ee 100644 --- a/src/RekognitionRequest.php +++ b/src/RekognitionRequest.php @@ -4,25 +4,18 @@ namespace MoeMizrak\Rekognition; -use Illuminate\Support\Arr; +use MoeMizrak\Rekognition\Data\CreateCollectionData; +use MoeMizrak\Rekognition\Data\DeleteCollectionData; use MoeMizrak\Rekognition\Data\DetectLabelsData; -use MoeMizrak\Rekognition\Data\ResultData\AliasData; -use MoeMizrak\Rekognition\Data\ResultData\BackgroundData; -use MoeMizrak\Rekognition\Data\ResultData\BoundingBoxData; -use MoeMizrak\Rekognition\Data\ResultData\CategoryData; -use MoeMizrak\Rekognition\Data\ResultData\DominantColorsData; -use MoeMizrak\Rekognition\Data\ResultData\ForegroundData; -use MoeMizrak\Rekognition\Data\ResultData\ImagePropertiesData; -use MoeMizrak\Rekognition\Data\ResultData\InstanceData; -use MoeMizrak\Rekognition\Data\ResultData\LabelData; -use MoeMizrak\Rekognition\Data\ResultData\MetaData; -use MoeMizrak\Rekognition\Data\ResultData\ParentData; -use MoeMizrak\Rekognition\Data\ResultData\QualityData; -use MoeMizrak\Rekognition\Data\ResultData\ResultData; -use Spatie\LaravelData\DataCollection; +use MoeMizrak\Rekognition\Data\ListCollectionsData; +use MoeMizrak\Rekognition\Data\ResultData\CreateCollectionResultData; +use MoeMizrak\Rekognition\Data\ResultData\DeleteCollectionResultData; +use MoeMizrak\Rekognition\Data\ResultData\ListCollectionsResultData; +use MoeMizrak\Rekognition\Data\ResultData\DetectLabelsResultData; /** * RekognitionRequest is the class that sends requests to AWS Rekognition API. + * For more information, see https://docs.aws.amazon.com/aws-sdk-php/v3/api/api-rekognition-2016-06-27.html * * @class RekognitionRequest */ @@ -34,259 +27,63 @@ * * @param DetectLabelsData $detectLabelsData * - * @return ResultData + * @return DetectLabelsResultData */ - public function detectLabels(DetectLabelsData $detectLabelsData): ResultData + public function detectLabels(DetectLabelsData $detectLabelsData): DetectLabelsResultData { - // Send the request to AWS Rekognition API. + // Send the request to AWS Rekognition API for detecting labels. $response = $this->client->detectLabels($detectLabelsData->toRekognitionDataFormat()); // Form the response before returning it. - return $this->formDetectLabelsResponse($response->toArray()); + return $this->rekognitionHelper->formDetectLabelsResponse($response->toArray()); } /** - * Forms the Rekognition detect labels response to ResultData including labels, label model version, orientation correction, image properties, and metadata. + * Lists the collections in the AWS account. * - * @param array $response + * @param ListCollectionsData $listCollectionsData * - * @return ResultData + * @return ListCollectionsResultData */ - private function formDetectLabelsResponse(array $response): ResultData + public function listCollections(ListCollectionsData $listCollectionsData): ListCollectionsResultData { - return new ResultData( - labels : $this->retrieveLabels($response), - LabelModelVersion : Arr::get($response, 'LabelModelVersion'), - orientationCorrection: Arr::get($response, 'OrientationCorrection'), - imageProperties : $this->retrieveImageProperties($response), - metadata : $this->retrieveMetaData($response), - ); - } - - /** - * Retrieves the metadata of the response including status code, effective uri, headers, and transfer stats. - * - * @param array $response - * - * @return MetaData - */ - private function retrieveMetaData(array $response): MetaData - { - return new MetaData( - statusCode : Arr::get($response, '@metadata.statusCode'), - effectiveUri : Arr::get($response, '@metadata.effectiveUri'), - headers : Arr::get($response, '@metadata.headers'), - transferStats : Arr::get($response, '@metadata.transferStats'), - ); - } - - /** - * Retrieves the image properties of the response including background, dominant colors, foreground, and quality. - * - * @param array $response - * - * @return ImagePropertiesData - */ - private function retrieveImageProperties(array $response): ImagePropertiesData - { - $dominantColors = []; - $returnedImageProperties = Arr::get($response, 'ImageProperties', []); - $returnedDominantColors = Arr::get($returnedImageProperties, 'DominantColors', []); - - // Map the dominant colors data and add them to the dominant colors array. - foreach ($returnedDominantColors as $returnedDominantColor) { - $returnedDominantColor = new DominantColorsData( - blue : Arr::get($returnedDominantColor, 'Blue'), - cssColor : Arr::get($returnedDominantColor, 'CSSColor'), - green : Arr::get($returnedDominantColor, 'Green'), - hexCode : Arr::get($returnedDominantColor, 'HexCode'), - pixelPercent : Arr::get($returnedDominantColor, 'PixelPercent'), - red : Arr::get($returnedDominantColor, 'Red'), - simplifiedColor: Arr::get($returnedDominantColor, 'SimplifiedColor'), - ); - - $dominantColors[] = $returnedDominantColor; - } - - $returnedQuality = Arr::get($returnedImageProperties, 'Quality'); - - $quality = new QualityData( - brightness: Arr::get($returnedQuality, 'Brightness'), - contrast : Arr::get($returnedQuality, 'Contrast'), - sharpness : Arr::get($returnedQuality, 'Sharpness'), - ); - - return new ImagePropertiesData( - background : $this->retrieveBackgroundImageProperty($returnedImageProperties), - dominantColors: new DataCollection(DominantColorsData::class, $dominantColors), - foreground : $this->retrieveForegroundImageProperty($returnedImageProperties), - quality : $quality, - ); - } - - /** - * Retrieves the foreground image property including dominant colors and quality. - * - * @param array|null $returnedImageProperties - * - * @return ForegroundData - */ - private function retrieveForegroundImageProperty(?array $returnedImageProperties): ForegroundData - { - $returnedForeground = Arr::get($returnedImageProperties, 'Foreground'); - $returnedForegroundDominantColors = Arr::get($returnedForeground, 'DominantColors'); - $returnedQuality = Arr::get($returnedForeground, 'Quality'); - - return new ForegroundData( - dominantColors: $this->mapDominantColors($returnedForegroundDominantColors), - quality : $this->mapQualityData($returnedQuality), - ); - } - - /** - * Retrieves the background image property including dominant colors and quality. - * - * @param array|null $returnedImageProperties - * - * @return BackgroundData - */ - private function retrieveBackgroundImageProperty(?array $returnedImageProperties): BackgroundData - { - $returnedBackground = Arr::get($returnedImageProperties, 'Background'); - $returnedBackgroundDominantColors = Arr::get($returnedBackground, 'DominantColors'); - $returnedQuality = Arr::get($returnedBackground, 'Quality'); + // Send the request to AWS Rekognition API for listing collections. + $response = $this->client->listCollections($listCollectionsData->toRekognitionDataFormat()); - return new BackgroundData( - dominantColors: $this->mapDominantColors($returnedBackgroundDominantColors), - quality : $this->mapQualityData($returnedQuality), - ); + // Form the response before returning it. + return $this->rekognitionHelper->formListCollectionsResponse($response->toArray()); } /** - * Maps the dominant colors data and returns a DataCollection of DominantColorsData. + * Creates a collection in an AWS account. * - * @param array|null $returnedColors + * @param CreateCollectionData $createCollectionData * - * @return DataCollection + * @return CreateCollectionResultData */ - private function mapDominantColors(?array $returnedColors): DataCollection + public function createCollection(CreateCollectionData $createCollectionData): CreateCollectionResultData { - $dominantColors = array_map(function ($color) { - return new DominantColorsData( - blue : Arr::get($color, 'Blue'), - cssColor : Arr::get($color, 'CSSColor'), - green : Arr::get($color, 'Green'), - hexCode : Arr::get($color, 'HexCode'), - pixelPercent : Arr::get($color, 'PixelPercent'), - red : Arr::get($color, 'Red'), - simplifiedColor: Arr::get($color, 'SimplifiedColor'), - ); - }, $returnedColors ?? []); - - return new DataCollection(DominantColorsData::class, $dominantColors); - } + // Send the request to AWS Rekognition API for creating a collection. + $response = $this->client->createCollection($createCollectionData->toRekognitionDataFormat()); - /** - * Maps the quality data and returns a QualityData object. - * - * @param array|null $returnedQuality - * - * @return QualityData - */ - private function mapQualityData(?array $returnedQuality): QualityData - { - return new QualityData( - brightness: Arr::get($returnedQuality, 'Brightness'), - contrast : Arr::get($returnedQuality, 'Contrast'), - sharpness : Arr::get($returnedQuality, 'Sharpness'), - ); + // Form the response before returning it. + return $this->rekognitionHelper->formCreateCollectionResponse($response->toArray()); } /** - * Retrieves the labels of the response including name, confidence, instances, parents, aliases, and categories. + * Deletes the specified collection with the provided collection ID. + * Warning! Note that this operation removes all faces in the collection. * - * @param array $response + * @param DeleteCollectionData $deleteCollectionData * - * @return DataCollection + * @return DeleteCollectionResultData */ - private function retrieveLabels(array $response): DataCollection + public function deleteCollection(DeleteCollectionData $deleteCollectionData): DeleteCollectionResultData { - $labels = []; - $returnedLabels = Arr::get($response, 'Labels', []); - - // Loop through the returned labels and map them accordingly. - foreach ($returnedLabels as $returnedLabel) { - $instances = []; - $name = Arr::get($returnedLabel, 'Name'); - $confidence = Arr::get($returnedLabel, 'Confidence'); - $returnedInstances = Arr::get($returnedLabel, 'Instances', []); - - // Loop through the returned instances of the returned label and map them accordingly and add them to the instances array. - foreach ($returnedInstances as $returnedInstance) { - $returnedBoundingBox = Arr::get($returnedInstance, 'BoundingBox'); - $returnedConfidence = Arr::get($returnedInstance, 'Confidence'); + // Send the request to AWS Rekognition API for deleting a collection. + $response = $this->client->deleteCollection($deleteCollectionData->toRekognitionDataFormat()); - $boundingBox = new BoundingBoxData( - height: Arr::get($returnedBoundingBox, 'Height'), - left : Arr::get($returnedBoundingBox, 'Left'), - top : Arr::get($returnedBoundingBox, 'Top'), - width : Arr::get($returnedBoundingBox, 'Width'), - ); - - $instance = new InstanceData( - boundingBox: $boundingBox, - confidence : $returnedConfidence, - ); - - $instances[] = $instance; - } - - $parents = []; - $returnedParents = Arr::get($returnedLabel, 'Parents', []); - - // Loop through the returned parents and map them accordingly, and add them to the parents array. - foreach ($returnedParents as $returnedParent) { - $parent = new ParentData( - name: Arr::get($returnedParent, 'Name'), - ); - - $parents[] = $parent; - } - - $aliases = []; - $returnedAliases = Arr::get($returnedLabel, 'Aliases', []); - - foreach ($returnedAliases as $returnedAlias) { - $aliasesItem = new AliasData( - name: Arr::get($returnedAlias, 'Name'), - ); - - $aliases[] = $aliasesItem; - } - - $categories = []; - $returnedCategories = Arr::get($returnedLabel, 'Categories', []); - - foreach ($returnedCategories as $returnedCategory) { - $category = new CategoryData( - name: Arr::get($returnedCategory, 'Name'), - ); - - $categories[] = $category; - } - - $label = new LabelData( - aliases : new DataCollection(AliasData::class, $aliases), - categories: new DataCollection(CategoryData::class, $categories), - confidence: $confidence, - instances : new DataCollection(InstanceData::class, $instances), - name : $name, - parents : new DataCollection(ParentData::class, $parents), - ); - - $labels[] = $label; - } - - return new DataCollection(LabelData::class, $labels); + // Form the response before returning it. + return $this->rekognitionHelper->formDeleteCollectionResponse($response->toArray()); } } \ No newline at end of file diff --git a/src/RekognitionServiceProvider.php b/src/RekognitionServiceProvider.php index ce94a03..e789371 100644 --- a/src/RekognitionServiceProvider.php +++ b/src/RekognitionServiceProvider.php @@ -6,6 +6,7 @@ use Illuminate\Foundation\AliasLoader; use Illuminate\Support\ServiceProvider; use MoeMizrak\Rekognition\Facades\Rekognition; +use MoeMizrak\Rekognition\Helpers\RekognitionHelper; /** * Service provider for Rekognition. @@ -46,6 +47,7 @@ public function register(): void $this->app->bind('aws-rekognition', function () { return new RekognitionRequest( $this->app->make(RekognitionClient::class), + new RekognitionHelper(), ); }); diff --git a/tests/RekognitionRequestTest.php b/tests/RekognitionRequestTest.php index 3910664..5e0bd79 100644 --- a/tests/RekognitionRequestTest.php +++ b/tests/RekognitionRequestTest.php @@ -2,8 +2,11 @@ namespace MoeMizrak\Rekognition\Tests; +use MoeMizrak\Rekognition\Data\CreateCollectionData; +use MoeMizrak\Rekognition\Data\DeleteCollectionData; use MoeMizrak\Rekognition\Data\DetectLabelsData; use MoeMizrak\Rekognition\Data\ImageData; +use MoeMizrak\Rekognition\Data\ListCollectionsData; use MoeMizrak\Rekognition\Data\S3ObjectData; use MoeMizrak\Rekognition\Facades\Rekognition; use PHPUnit\Framework\Attributes\Test; @@ -30,6 +33,7 @@ public function it_test_detect_labels_request_of_image_sent() { /* SETUP */ $imagePath = __DIR__.'/resources/images/test_labels.jpg'; + $methodName = 'detectLabels'; $image = file_get_contents($imagePath); $imageData = new ImageData( bytes: $image, @@ -38,7 +42,7 @@ public function it_test_detect_labels_request_of_image_sent() image: $imageData, maxLabels: 5, ); - $this->mockDetectLabelsRequest(); + $this->mockRekognitionClient($methodName); /* EXECUTE */ $response = Rekognition::detectLabels($detectLabelsData); @@ -46,13 +50,14 @@ public function it_test_detect_labels_request_of_image_sent() /* ASSERT */ $this->metaDataAssertions($response); $this->assertInstanceOf(DataCollection::class, $response->labels); - $this->assertNotNull($response->LabelModelVersion); + $this->assertNotNull($response->labelModelVersion); } #[Test] public function it_test_detect_labels_request_of_s3_image() { /* SETUP */ + $methodName = 'detectLabels'; $s3Object = new S3ObjectData( bucket: 'test_bucket_name', name: 'test_image_key_name.jpg', @@ -65,7 +70,7 @@ public function it_test_detect_labels_request_of_s3_image() image: $imageData, maxLabels: 5, ); - $this->mockDetectLabelsRequest(); + $this->mockRekognitionClient($methodName); /* EXECUTE */ $response = Rekognition::detectLabels($detectLabelsData); @@ -73,6 +78,66 @@ public function it_test_detect_labels_request_of_s3_image() /* ASSERT */ $this->metaDataAssertions($response); $this->assertInstanceOf(DataCollection::class, $response->labels); - $this->assertNotNull($response->LabelModelVersion); + $this->assertNotNull($response->labelModelVersion); + } + + #[Test] + public function it_tests_create_collection_request_for_given_collection_id_and_tags() + { + /* SETUP */ + $methodName = 'createCollection'; + $collectionId = 'test_collection_id_0'; + $createCollectionData = new CreateCollectionData( + collectionId: $collectionId, + ); + $this->mockRekognitionClient($methodName); + + /* EXECUTE */ + $response = Rekognition::createCollection($createCollectionData); + + /* ASSERT */ + $this->metaDataAssertions($response); + $this->assertNotNull($response->collectionArn); + $this->assertNotNull($response->faceModelVersion); + $this->assertEquals(200, $response->statusCode); + $this->assertStringContainsString($collectionId, $response->collectionArn); + } + + #[Test] + public function it_tests_list_collections_request() + { + /* SETUP */ + $methodName = 'listCollections'; + $listCollectionsData = new ListCollectionsData(); + $this->mockRekognitionClient($methodName); + + /* EXECUTE */ + $response = Rekognition::listCollections($listCollectionsData); + + /* ASSERT */ + $this->metaDataAssertions($response); + $this->assertIsArray($response->collectionIds); + $this->assertIsArray($response->faceModelVersions); + $this->assertContains('test_collection_id_0', $response->collectionIds); + $this->assertContains('test_collection_id_1', $response->collectionIds); + } + + #[Test] + public function it_tests_delete_collection_request_for_given_collection_id() + { + /* SETUP */ + $methodName = 'deleteCollection'; + $deleteCollectionId = 'test_collection_id_2'; + $deleteCollectionData = new DeleteCollectionData( + collectionId: $deleteCollectionId, + ); + $this->mockRekognitionClient($methodName); + + /* EXECUTE */ + $response = Rekognition::deleteCollection($deleteCollectionData); + + /* ASSERT */ + $this->metaDataAssertions($response); + $this->assertEquals(200, $response->statusCode); } } \ No newline at end of file diff --git a/tests/TestCase.php b/tests/TestCase.php index 0d8636b..847adef 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -3,14 +3,16 @@ namespace MoeMizrak\Rekognition\Tests; use Aws\Rekognition\RekognitionClient; -use Aws\Result; use Mockery\MockInterface; use MoeMizrak\Rekognition\Facades\Rekognition; use MoeMizrak\Rekognition\RekognitionServiceProvider; +use MoeMizrak\Rekognition\Tests\Traits\MockTrait; use Orchestra\Testbench\TestCase as OrchestraTestCase; class TestCase extends OrchestraTestCase { + use MockTrait; + /** * @return void */ @@ -44,226 +46,20 @@ protected function getPackageAliases($app): array } /** - * Mock the detect labels request for testing in order to avoid making real requests. + * Mock the Rekognition client for testing in order to avoid making real requests. + * + * @param string $methodName * * @return void */ - protected function mockDetectLabelsRequest(): void + protected function mockRekognitionClient(string $methodName): void { - $mockResponse = $this->mockDetectLabelsBody(); + $mockResponse = $this->mockRekognitionResponse($methodName); - $this->mock(RekognitionClient::class, function (MockInterface $mock) use ($mockResponse) { - $mock->shouldReceive('detectLabels') + $this->mock(RekognitionClient::class, function (MockInterface $mock) use($methodName, $mockResponse) { + $mock->shouldReceive($methodName) ->once() ->andReturn($mockResponse); }); } - - /** - * Mock the detect labels response body. This is the response that would be returned from the AWS Rekognition API. - * - * @return Result - */ - private function mockDetectLabelsBody(): Result - { - $data = [ - "Labels" => [ - [ - "Name" => "Adult", - "Confidence" => 99.406089782715, - "Instances" => [ - [ - "BoundingBox" => [ - "Width" => 0.4137507379055, - "Height" => 0.74068546295166, - "Left" => 0.0, - "Top" => 0.25919502973557, - ], - "Confidence" => 99.406089782715, - ], - [ - "BoundingBox" => [ - "Width" => 0.4726165831089, - "Height" => 0.55402708053589, - "Left" => 0.29312029480934, - "Top" => 0.23203137516975, - ], - "Confidence" => 98.74324798584, - ], - [ - "BoundingBox" => [ - "Width" => 0.29476174712181, - "Height" => 0.62268280982971, - "Left" => 0.64589500427246, - "Top" => 0.26460602879524, - ], - "Confidence" => 98.648498535156, - ], - ], - "Parents" => [ - ["Name" => "Person"], - ], - "Aliases" => [], - "Categories" => [ - ["Name" => "Person Description"], - ], - ], - [ - "Name" => "Male", - "Confidence" => 99.406089782715, - "Instances" => [ - [ - "BoundingBox" => [ - "Width" => 0.4137507379055, - "Height" => 0.74068546295166, - "Left" => 0.0, - "Top" => 0.25919502973557, - ], - "Confidence" => 99.406089782715, - ], - [ - "BoundingBox" => [ - "Width" => 0.40260022878647, - "Height" => 0.50842136144638, - "Left" => 0.5948948264122, - "Top" => 0.49154290556908, - ], - "Confidence" => 98.609413146973, - ], - ], - "Parents" => [ - ["Name" => "Person"], - ], - "Aliases" => [], - "Categories" => [ - ["Name" => "Person Description"], - ], - ], - [ - "Name" => "Man", - "Confidence" => 99.406089782715, - "Instances" => [ - [ - "BoundingBox" => [ - "Width" => 0.4137507379055, - "Height" => 0.74068546295166, - "Left" => 0.0, - "Top" => 0.25919502973557, - ], - "Confidence" => 99.406089782715, - ], - ], - "Parents" => [ - ["Name" => "Adult"], - ["Name" => "Male"], - ["Name" => "Person"], - ], - "Aliases" => [], - "Categories" => [ - ["Name" => "Person Description"], - ], - ], - [ - "Name" => "Person", - "Confidence" => 99.406089782715, - "Instances" => [ - [ - "BoundingBox" => [ - "Width" => 0.4137507379055, - "Height" => 0.74068546295166, - "Left" => 0.0, - "Top" => 0.25919502973557, - ], - "Confidence" => 99.406089782715, - ], - [ - "BoundingBox" => [ - "Width" => 0.4726165831089, - "Height" => 0.55402708053589, - "Left" => 0.29312029480934, - "Top" => 0.23203137516975, - ], - "Confidence" => 98.74324798584, - ], - [ - "BoundingBox" => [ - "Width" => 0.29476174712181, - "Height" => 0.62268280982971, - "Left" => 0.64589500427246, - "Top" => 0.26460602879524, - ], - "Confidence" => 98.648498535156, - ], - [ - "BoundingBox" => [ - "Width" => 0.40260022878647, - "Height" => 0.50842136144638, - "Left" => 0.5948948264122, - "Top" => 0.49154290556908, - ], - "Confidence" => 98.609413146973, - ], - ], - "Parents" => [], - "Aliases" => [ - ["Name" => "Human"], - ], - "Categories" => [ - ["Name" => "Person Description"], - ], - ], - [ - "Name" => "Woman", - "Confidence" => 98.74324798584, - "Instances" => [ - [ - "BoundingBox" => [ - "Width" => 0.4726165831089, - "Height" => 0.55402708053589, - "Left" => 0.29312029480934, - "Top" => 0.23203137516975, - ], - "Confidence" => 98.74324798584, - ], - [ - "BoundingBox" => [ - "Width" => 0.29476174712181, - "Height" => 0.62268280982971, - "Left" => 0.64589500427246, - "Top" => 0.26460602879524, - ], - "Confidence" => 98.648498535156, - ], - ], - "Parents" => [ - ["Name" => "Adult"], - ["Name" => "Female"], - ["Name" => "Person"], - ], - "Aliases" => [], - "Categories" => [ - ["Name" => "Person Description"], - ], - ], - ], - "LabelModelVersion" => "3.0", - "@metadata" => [ - "statusCode" => 200, - "effectiveUri" => "https://rekognition.us-east-1.amazonaws.com", - "headers" => [ - "x-amzn-requestid" => "8dc27697-dc77-4d24-9f68-1f5080b536c2", - "content-type" => "application/x-amz-json-1.1", - "content-length" => "2658", - "date" => "Fri, 17 Jan 2025 18:05:24 GMT", - ], - "transferStats" => [ - "http" => [ - [], - ], - ], - ], - ]; - - return new Result($data); - } } \ No newline at end of file diff --git a/tests/Traits/MockTrait.php b/tests/Traits/MockTrait.php new file mode 100644 index 0000000..764f6b8 --- /dev/null +++ b/tests/Traits/MockTrait.php @@ -0,0 +1,305 @@ + $this->mockDetectLabelsBody(), + 'createCollection' => $this->mockCreateCollectionBody(), + 'deleteCollection' => $this->mockDeleteCollectionBody(), + 'listCollections' => $this->mockListCollectionsBody(), + default => new Result([]), + }; + } + + /** + * Mock the list collections response body. This is the response that would be returned from the AWS Rekognition API listCollections call. + * + * @return Result + */ + private function mockListCollectionsBody(): Result + { + $data = [ + 'CollectionIds' => [ + 'test_collection_id_0', + 'test_collection_id_1', + ], + 'FaceModelVersions' => [ + '7.0', + '7.0', + ], + "@metadata" => $this->mockMetadata(), + ]; + + return new Result($data); + } + + /** + * Mock the create collection response body. This is the response that would be returned from the AWS Rekognition API createCollection call. + * + * @return Result + */ + private function mockCreateCollectionBody(): Result + { + $data = [ + "CollectionArn" => "aws:rekognition:us-east-1:605134457385:collection/test_collection_id_0", + "FaceModelVersion" => "7.0", + "StatusCode" => 200, + "@metadata" => $this->mockMetadata(), + ]; + + return new Result($data); + } + + /** + * Mock the delete collection response body. This is the response that would be returned from the AWS Rekognition API deleteCollection call. + * + * @return Result + */ + private function mockDeleteCollectionBody(): Result + { + $data = [ + "StatusCode" => 200, + "@metadata" => $this->mockMetadata(), + ]; + + return new Result($data); + } + + /** + * Mock the detect labels response body. This is the response that would be returned from the AWS Rekognition API detectLabels call. + * + * @return Result + */ + private function mockDetectLabelsBody(): Result + { + $data = [ + "Labels" => [ + [ + "Name" => "Adult", + "Confidence" => 99.406089782715, + "Instances" => [ + [ + "BoundingBox" => [ + "Width" => 0.4137507379055, + "Height" => 0.74068546295166, + "Left" => 0.0, + "Top" => 0.25919502973557, + ], + "Confidence" => 99.406089782715, + ], + [ + "BoundingBox" => [ + "Width" => 0.4726165831089, + "Height" => 0.55402708053589, + "Left" => 0.29312029480934, + "Top" => 0.23203137516975, + ], + "Confidence" => 98.74324798584, + ], + [ + "BoundingBox" => [ + "Width" => 0.29476174712181, + "Height" => 0.62268280982971, + "Left" => 0.64589500427246, + "Top" => 0.26460602879524, + ], + "Confidence" => 98.648498535156, + ], + ], + "Parents" => [ + ["Name" => "Person"], + ], + "Aliases" => [], + "Categories" => [ + ["Name" => "Person Description"], + ], + ], + [ + "Name" => "Male", + "Confidence" => 99.406089782715, + "Instances" => [ + [ + "BoundingBox" => [ + "Width" => 0.4137507379055, + "Height" => 0.74068546295166, + "Left" => 0.0, + "Top" => 0.25919502973557, + ], + "Confidence" => 99.406089782715, + ], + [ + "BoundingBox" => [ + "Width" => 0.40260022878647, + "Height" => 0.50842136144638, + "Left" => 0.5948948264122, + "Top" => 0.49154290556908, + ], + "Confidence" => 98.609413146973, + ], + ], + "Parents" => [ + ["Name" => "Person"], + ], + "Aliases" => [], + "Categories" => [ + ["Name" => "Person Description"], + ], + ], + [ + "Name" => "Man", + "Confidence" => 99.406089782715, + "Instances" => [ + [ + "BoundingBox" => [ + "Width" => 0.4137507379055, + "Height" => 0.74068546295166, + "Left" => 0.0, + "Top" => 0.25919502973557, + ], + "Confidence" => 99.406089782715, + ], + ], + "Parents" => [ + ["Name" => "Adult"], + ["Name" => "Male"], + ["Name" => "Person"], + ], + "Aliases" => [], + "Categories" => [ + ["Name" => "Person Description"], + ], + ], + [ + "Name" => "Person", + "Confidence" => 99.406089782715, + "Instances" => [ + [ + "BoundingBox" => [ + "Width" => 0.4137507379055, + "Height" => 0.74068546295166, + "Left" => 0.0, + "Top" => 0.25919502973557, + ], + "Confidence" => 99.406089782715, + ], + [ + "BoundingBox" => [ + "Width" => 0.4726165831089, + "Height" => 0.55402708053589, + "Left" => 0.29312029480934, + "Top" => 0.23203137516975, + ], + "Confidence" => 98.74324798584, + ], + [ + "BoundingBox" => [ + "Width" => 0.29476174712181, + "Height" => 0.62268280982971, + "Left" => 0.64589500427246, + "Top" => 0.26460602879524, + ], + "Confidence" => 98.648498535156, + ], + [ + "BoundingBox" => [ + "Width" => 0.40260022878647, + "Height" => 0.50842136144638, + "Left" => 0.5948948264122, + "Top" => 0.49154290556908, + ], + "Confidence" => 98.609413146973, + ], + ], + "Parents" => [], + "Aliases" => [ + ["Name" => "Human"], + ], + "Categories" => [ + ["Name" => "Person Description"], + ], + ], + [ + "Name" => "Woman", + "Confidence" => 98.74324798584, + "Instances" => [ + [ + "BoundingBox" => [ + "Width" => 0.4726165831089, + "Height" => 0.55402708053589, + "Left" => 0.29312029480934, + "Top" => 0.23203137516975, + ], + "Confidence" => 98.74324798584, + ], + [ + "BoundingBox" => [ + "Width" => 0.29476174712181, + "Height" => 0.62268280982971, + "Left" => 0.64589500427246, + "Top" => 0.26460602879524, + ], + "Confidence" => 98.648498535156, + ], + ], + "Parents" => [ + ["Name" => "Adult"], + ["Name" => "Female"], + ["Name" => "Person"], + ], + "Aliases" => [], + "Categories" => [ + ["Name" => "Person Description"], + ], + ], + ], + "LabelModelVersion" => "3.0", + "@metadata" => $this->mockMetadata(), + ]; + + return new Result($data); + } + + /** + * Mock the metadata. + * + * @return array + */ + private function mockMetadata(): array + { + return [ + "statusCode" => 200, + "effectiveUri" => "https://rekognition.us-east-1.amazonaws.com", + "headers" => [ + "x-amzn-requestid" => "8dc27697-dc77-4d24-9f68-1f5080b536c2", + "content-type" => "application/x-amz-json-1.1", + "content-length" => "2658", + "date" => "Fri, 17 Jan 2025 18:05:24 GMT", + ], + "transferStats" => [ + "http" => [ + [], + ], + ], + ]; + } +} \ No newline at end of file