From cabf6a36562ce55e684d727f2ee08ac7d850ced4 Mon Sep 17 00:00:00 2001 From: Tom Van Herreweghe Date: Sun, 29 Mar 2015 19:21:12 +0200 Subject: [PATCH 01/38] Add Mutator Hydrator for hydrating Exif objects Signed-off-by: Tom Van Herreweghe --- lib/PHPExif/Hydrator/HydratorInterface.php | 33 +++++++++++++ lib/PHPExif/Hydrator/Mutator.php | 56 ++++++++++++++++++++++ 2 files changed, 89 insertions(+) create mode 100644 lib/PHPExif/Hydrator/HydratorInterface.php create mode 100644 lib/PHPExif/Hydrator/Mutator.php diff --git a/lib/PHPExif/Hydrator/HydratorInterface.php b/lib/PHPExif/Hydrator/HydratorInterface.php new file mode 100644 index 0000000..8f81bdd --- /dev/null +++ b/lib/PHPExif/Hydrator/HydratorInterface.php @@ -0,0 +1,33 @@ + + * @license http://github.com/miljar/PHPExif/blob/master/LICENSE MIT License + * @category PHPExif + * @package Hydrator + */ + +namespace PHPExif\Hydrator; + +/** + * PHP Exif Hydrator + * + * Defines the interface for a hydrator + * + * @category PHPExif + * @package Hydrator + */ +interface HydratorInterface +{ + /** + * Hydrates given array of data into the given Exif object + * + * @param object $object + * @param array $data + * @return void + */ + public function hydrate($object, array $data); +} + diff --git a/lib/PHPExif/Hydrator/Mutator.php b/lib/PHPExif/Hydrator/Mutator.php new file mode 100644 index 0000000..52559d1 --- /dev/null +++ b/lib/PHPExif/Hydrator/Mutator.php @@ -0,0 +1,56 @@ + + * @license http://github.com/miljar/PHPExif/blob/master/LICENSE MIT License + * @category PHPExif + * @package Hydrator + */ + +namespace PHPExif\Hydrator; + +/** + * PHP Exif Mutator Hydrator + * + * Hydrates an object by setting data with + * the class mutator methods + * + * @category PHPExif + * @package Hydrator + */ +class Mutator implements HydratorInterface +{ + /** + * Hydrates given array of data into the given Exif object + * + * @param object $object + * @param array $data + * @return void + */ + public function hydrate($object, array $data) + { + foreach ($data as $property => $value) { + $mutator = $this->determineMutator($property); + + if (method_exists($object, $mutator)) { + $object->$mutator($value); + } + } + } + + /** + * Determines the name of the mutator method for given property name + * + * @param string $property The property to determine the mutator for + * @return string The name of the mutator method + */ + protected function determineMutator($property) + { + $method = 'set' . ucfirst($property); + return $method; + } +} + From 8f6cdc03d90fef6c69b1a4b8f5803ab743028bfe Mon Sep 17 00:00:00 2001 From: Tom Van Herreweghe Date: Sun, 29 Mar 2015 19:21:41 +0200 Subject: [PATCH 02/38] Add separate mappers for mapping data to Exif object format Signed-off-by: Tom Van Herreweghe --- lib/PHPExif/Mapper/Exiftool.php | 134 +++++++++++++++++++++ lib/PHPExif/Mapper/MapperInterface.php | 33 ++++++ lib/PHPExif/Mapper/Native.php | 157 +++++++++++++++++++++++++ 3 files changed, 324 insertions(+) create mode 100644 lib/PHPExif/Mapper/Exiftool.php create mode 100644 lib/PHPExif/Mapper/MapperInterface.php create mode 100644 lib/PHPExif/Mapper/Native.php diff --git a/lib/PHPExif/Mapper/Exiftool.php b/lib/PHPExif/Mapper/Exiftool.php new file mode 100644 index 0000000..27dbbe2 --- /dev/null +++ b/lib/PHPExif/Mapper/Exiftool.php @@ -0,0 +1,134 @@ + + * @license http://github.com/miljar/PHPExif/blob/master/LICENSE MIT License + * @category PHPExif + * @package Mapper + */ + +namespace PHPExif\Mapper; + +use PHPExif\Exif; +use DateTime; + +/** + * PHP Exif Exiftool Mapper + * + * Maps Exiftool raw data to valid data for the \PHPExif\Exif class + * + * @category PHPExif + * @package Mapper + */ +class Exiftool implements MapperInterface +{ + const APERTURE = 'Aperture'; + const APPROXIMATEFOCUSDISTANCE = 'ApproximateFocusDistance'; + const ARTIST = 'Artist'; + const CAPTION = 'Caption'; + const CAPTIONABSTRACT = 'Caption-Abstract'; + const COLORSPACE = 'ColorSpace'; + const COPYRIGHT = 'Copyright'; + const CREATIONDATE = 'CreationDate'; + const CREDIT = 'Credit'; + const EXPOSURETIME = 'ExposureTime'; + const FILESIZE = 'FileSize'; + const FOCALLENGTH = 'FocalLength'; + const HEADLINE = 'Headline'; + const IMAGEHEIGHT = 'ImageHeight'; + const IMAGEWIDTH = 'ImageWidth'; + const ISO = 'ISO'; + const JOBTITLE = 'JobTitle'; + const KEYWORDS = 'Keywords'; + const MIMETYPE = 'MIMEType'; + const MODEL = 'Model'; + const ORIENTATION = 'Orientation'; + const SOFTWARE = 'Software'; + const SOURCE = 'Source'; + const TITLE = 'Title'; + const XRESOLUTION = 'XResolution'; + const YRESOLUTION = 'YResolution'; + + /** + * Maps the ExifTool fields to the fields of + * the \PHPExif\Exif class + * + * @var array + */ + protected $map = array( + self::APERTURE => Exif::APERTURE, + self::ARTIST => Exif::AUTHOR, + self::MODEL => Exif::CAMERA, + self::CAPTION => Exif::CAPTION, + self::CAPTIONABSTRACT => Exif::CAPTION, + self::COLORSPACE => Exif::COLORSPACE, + self::COPYRIGHT => Exif::COPYRIGHT, + self::CREATIONDATE => Exif::CREATION_DATE, + self::CREDIT => Exif::CREDIT, + self::EXPOSURETIME => Exif::EXPOSURE, + self::FILESIZE => Exif::FILESIZE, + self::FOCALLENGTH => Exif::FOCAL_LENGTH, + self::APPROXIMATEFOCUSDISTANCE => Exif::FOCAL_DISTANCE, + self::HEADLINE => Exif::HEADLINE, + self::IMAGEHEIGHT => Exif::HEIGHT, + self::XRESOLUTION => Exif::HORIZONTAL_RESOLUTION, + self::ISO => Exif::ISO, + self::JOBTITLE => Exif::JOB_TITLE, + self::KEYWORDS => Exif::KEYWORDS, + self::MIMETYPE => Exif::MIMETYPE, + self::ORIENTATION => Exif::ORIENTATION, + self::SOFTWARE => Exif::SOFTWARE, + self::SOURCE => Exif::SOURCE, + self::TITLE => Exif::TITLE, + self::YRESOLUTION => Exif::VERTICAL_RESOLUTION, + self::IMAGEWIDTH => Exif::WIDTH, + ); + + /** + * Maps the array of raw source data to the correct + * fields for the \PHPExif\Exif class + * + * @param array $data + * @return void + */ + public function mapRawData(array $data) + { + $mappedData = array(); + foreach ($data as $field => $value) { + if (!array_key_exists($field, $this->map)) { + // silently ignore unknown fields + continue; + } + + $key = $this->map[$field]; + + // manipulate the value if necessary + switch ($field) { + case self::APERTURE: + $value = sprintf('f/%01.1f', $value); + break; + case self::APPROXIMATEFOCUSDISTANCE: + $value = sprintf('%1$sm', $value); + break; + case self::CREATIONDATE: + $value = DateTime::createFromFormat('Y:m:d H:i:s', $value); + break; + case self::EXPOSURETIME: + $value = '1/' . round(1 / $value); + break; + case self::FOCALLENGTH: + $focalLengthParts = explode(' ', $value); + $value = (int) reset($focalLengthParts); + break; + } + + // set end result + $mappedData[$key] = $value; + } + + return $mappedData; + } +} + diff --git a/lib/PHPExif/Mapper/MapperInterface.php b/lib/PHPExif/Mapper/MapperInterface.php new file mode 100644 index 0000000..234ca06 --- /dev/null +++ b/lib/PHPExif/Mapper/MapperInterface.php @@ -0,0 +1,33 @@ + + * @license http://github.com/miljar/PHPExif/blob/master/LICENSE MIT License + * @category PHPExif + * @package Mapper + */ + +namespace PHPExif\Mapper; + +/** + * PHP Exif Mapper + * + * Defines the interface for data mappers + * + * @category PHPExif + * @package Mapper + */ +interface MapperInterface +{ + /** + * Maps the array of raw source data to the correct + * fields for the \PHPExif\Exif class + * + * @param array $data + * @return void + */ + public function mapRawData(array $data); +} + diff --git a/lib/PHPExif/Mapper/Native.php b/lib/PHPExif/Mapper/Native.php new file mode 100644 index 0000000..ac36580 --- /dev/null +++ b/lib/PHPExif/Mapper/Native.php @@ -0,0 +1,157 @@ + + * @license http://github.com/miljar/PHPExif/blob/master/LICENSE MIT License + * @category PHPExif + * @package Mapper + */ + +namespace PHPExif\Mapper; + +use PHPExif\Exif; +use DateTime; + +/** + * PHP Exif Native Mapper + * + * Maps native raw data to valid data for the \PHPExif\Exif class + * + * @category PHPExif + * @package Mapper + */ +class Native implements MapperInterface +{ + const APERTUREFNUMBER = 'ApertureFNumber'; + const ARTIST = 'Artist'; + const CAPTION = 'caption'; + const COLORSPACE = 'ColorSpace'; + const COPYRIGHT = 'copyright'; + const DATETIMEORIGINAL = 'DateTimeOriginal'; + const CREDIT = 'credit'; + const EXPOSURETIME = 'ExposureTime'; + const FILESIZE = 'FileSize'; + const FOCALLENGTH = 'FocalLength'; + const FOCUSDISTANCE = 'FocusDistance'; + const HEADLINE = 'headline'; + const HEIGHT = 'Height'; + const ISOSPEEDRATINGS = 'ISOSpeedRatings'; + const JOBTITLE = 'jobtitle'; + const KEYWORDS = 'keywords'; + const MIMETYPE = 'MIMEType'; + const MODEL = 'Model'; + const ORIENTATION = 'Orientation'; + const SOFTWARE = 'Software'; + const SOURCE = 'source'; + const TITLE = 'title'; + const WIDTH = 'Width'; + const XRESOLUTION = 'XResolution'; + const YRESOLUTION = 'YResolution'; + + const SECTION_FILE = 'FILE'; + const SECTION_COMPUTED = 'COMPUTED'; + const SECTION_IFD0 = 'IFD0'; + const SECTION_THUMBNAIL = 'THUMBNAIL'; + const SECTION_COMMENT = 'COMMENT'; + const SECTION_EXIF = 'EXIF'; + const SECTION_ALL = 'ANY_TAG'; + const SECTION_IPTC = 'IPTC'; + + /** + * Maps the ExifTool fields to the fields of + * the \PHPExif\Exif class + * + * @var array + */ + protected $map = array( + //self::SECTION_COMPUTED => array( + self::APERTUREFNUMBER => Exif::APERTURE, + self::FOCUSDISTANCE => Exif::FOCAL_DISTANCE, + self::HEIGHT => Exif::HEIGHT, + self::WIDTH => Exif::WIDTH, + //), + //self::SECTION_IPTC => array( + self::CAPTION => Exif::CAPTION, + self::COPYRIGHT => Exif::COPYRIGHT, + self::CREDIT => Exif::CREDIT, + self::HEADLINE => Exif::HEADLINE, + self::JOBTITLE => Exif::JOB_TITLE, + self::KEYWORDS => Exif::KEYWORDS, + self::SOURCE => Exif::SOURCE, + self::TITLE => Exif::TITLE, + //), + self::ARTIST => Exif::AUTHOR, + self::MODEL => Exif::CAMERA, + self::COLORSPACE => Exif::COLORSPACE, + self::DATETIMEORIGINAL => Exif::CREATION_DATE, + self::EXPOSURETIME => Exif::EXPOSURE, + self::FILESIZE => Exif::FILESIZE, + self::FOCALLENGTH => Exif::FOCAL_LENGTH, + self::ISOSPEEDRATINGS => Exif::ISO, + self::MIMETYPE => Exif::MIMETYPE, + self::ORIENTATION => Exif::ORIENTATION, + self::SOFTWARE => Exif::SOFTWARE, + self::XRESOLUTION => Exif::HORIZONTAL_RESOLUTION, + self::YRESOLUTION => Exif::VERTICAL_RESOLUTION, + ); + + /** + * Maps the array of raw source data to the correct + * fields for the \PHPExif\Exif class + * + * @param array $data + * @return void + */ + public function mapRawData(array $data) + { + $mappedData = array(); + foreach ($data as $field => $value) { + if (is_string($field) && is_array($value)) { + $subData = $this->mapRawData($value); + + $mappedData = array_merge($mappedData, $subData); + continue; + } + + if (!array_key_exists($field, $this->map)) { + // silently ignore unknown fields + continue; + } + + $key = $this->map[$field]; + + // manipulate the value if necessary + switch ($field) { + case self::DATETIMEORIGINAL: + $value = DateTime::createFromFormat('Y:m:d H:i:s', $value); + break; + case self::EXPOSURETIME: + // normalize ExposureTime + // on one test image, it reported "10/300" instead of "1/30" + list($counter, $denominator) = explode('/', $value); + if (intval($counter) !== 1) { + $denominator /= $counter; + } + $value = '1/' . round($denominator); + break; + case self::FOCALLENGTH: + $parts = explode('/', $value); + $value = (int)reset($parts) / (int)end($parts); + break; + case self::XRESOLUTION: + case self::YRESOLUTION: + $resolutionParts = explode('/', $value); + $value = (int)reset($resolutionParts); + break; + } + + // set end result + $mappedData[$key] = $value; + } + + return $mappedData; + } +} + From bf6ad93a31e26d3234bdd69f2dcf3bf7d7cb3c38 Mon Sep 17 00:00:00 2001 From: Tom Van Herreweghe Date: Sun, 29 Mar 2015 19:28:11 +0200 Subject: [PATCH 03/38] AdapterAbstract now uses Hydrator for setOptions; Removed obsolete methods Signed-off-by: Tom Van Herreweghe --- lib/PHPExif/Adapter/AdapterAbstract.php | 110 +++++++++--------- tests/PHPExif/Adapter/AdapterAbstractTest.php | 97 +-------------- 2 files changed, 61 insertions(+), 146 deletions(-) diff --git a/lib/PHPExif/Adapter/AdapterAbstract.php b/lib/PHPExif/Adapter/AdapterAbstract.php index 1e4450f..d4b122e 100644 --- a/lib/PHPExif/Adapter/AdapterAbstract.php +++ b/lib/PHPExif/Adapter/AdapterAbstract.php @@ -11,6 +11,9 @@ namespace PHPExif\Adapter; +use PHPExif\Mapper\MapperInterface; +use PHPExif\Hydrator\HydratorInterface; + /** * PHP Exif Reader Adapter Abstract * @@ -21,6 +24,21 @@ */ abstract class AdapterAbstract implements AdapterInterface { + /** + * @var string + */ + protected $hydratorClass = '\\PHPExif\\Hydrator\\Mutator'; + + /** + * @var \PHPExif\Mapper\MapperInterface + */ + protected $mapper; + + /** + * @var \PHPExif\Hydrator\HydratorInterface + */ + protected $hydrator; + /** * Class constructor * @@ -34,88 +52,76 @@ public function __construct(array $options = array()) } /** - * Set array of options in the current object + * Mutator for the data mapper * - * @param array $options - * @return \PHPExif\Reader\AdapterAbstract + * @param \PHPExif\Mapper\MapperInterface $mapper + * @return \PHPExif\Adapter\AdapterInterface; */ - public function setOptions(array $options) + public function setMapper(MapperInterface $mapper) { - foreach ($options as $property => $value) { - $setter = $this->determinePropertySetter($property); - if (method_exists($this, $setter)) { - $this->$setter($value); - } - } + $this->mapper = $mapper; return $this; } /** - * Detemines the name of the getter method for given property name + * Accessor for the data mapper * - * @param string $property The property to determine the getter for - * @return string The name of the getter method + * @return \PHPExif\Mapper\MapperInterface */ - protected function determinePropertyGetter($property) + public function getMapper() { - $method = 'get' . ucfirst($property); - return $method; + if (null === $this->mapper) { + // lazy load one + $mapper = new $this->mapperClass; + + $this->setMapper($mapper); + } + + return $this->mapper; } /** - * Detemines the name of the setter method for given property name + * Mutator for the hydrator * - * @param string $property The property to determine the setter for - * @return string The name of the setter method + * @param \PHPExif\Hydrator\HydratorInterface $hydrator + * @return \PHPExif\Adapter\AdapterInterface; */ - protected function determinePropertySetter($property) + public function setHydrator(HydratorInterface $hydrator) { - $method = 'set' . ucfirst($property); - return $method; + $this->hydrator = $hydrator; + + return $this; } /** - * Get a list of the class constants prefixed with given $type + * Accessor for the data hydrator * - * @param string $type - * @return array + * @return \PHPExif\Hydrator\HydratorInterface */ - public function getClassConstantsOfType($type) + public function getHydrator() { - $class = new \ReflectionClass(get_called_class()); - $constants = $class->getConstants(); - - $list = array(); - $type = strtoupper($type) . '_'; - foreach ($constants as $key => $value) { - if (strpos($key, $type) === 0) { - $list[$key] = $value; - } + if (null === $this->hydrator) { + // lazy load one + $hydrator = new $this->hydratorClass; + + $this->setHydrator($hydrator); } - return $list; + + return $this->hydrator; } /** - * Returns an array notation of current instance + * Set array of options in the current object * - * @return array + * @param array $options + * @return \PHPExif\Reader\AdapterAbstract */ - public function toArray() + public function setOptions(array $options) { - $rc = new \ReflectionClass(get_class($this)); - $properties = $rc->getProperties(); - $arrResult = array(); - - foreach ($properties as $rp) { - /* @var $rp \ReflectionProperty */ - $getter = $this->determinePropertyGetter($rp->getName()); - if (!method_exists($this, $getter)) { - continue; - } - $arrResult[$rp->getName()] = $this->$getter(); - } + $hydrator = $this->getHydrator(); + $hydrator->hydrate($this, $options); - return $arrResult; + return $this; } } diff --git a/tests/PHPExif/Adapter/AdapterAbstractTest.php b/tests/PHPExif/Adapter/AdapterAbstractTest.php index 97d2794..fd52e37 100644 --- a/tests/PHPExif/Adapter/AdapterAbstractTest.php +++ b/tests/PHPExif/Adapter/AdapterAbstractTest.php @@ -12,97 +12,6 @@ public function setUp() $this->adapter = new \PHPExif\Adapter\Native(); } - /** - * @group adapter - * @covers \PHPExif\Adapter\AdapterAbstract::determinePropertyGetter - */ - public function testDeterminePropertyGetter() - { - $reflMethod = new \ReflectionMethod('\PHPExif\Adapter\Native', 'determinePropertyGetter'); - $reflMethod->setAccessible(true); - - $result = $reflMethod->invoke( - $this->adapter, - 'foo' - ); - - $this->assertEquals('getFoo', $result); - } - - /** - * @group adapter - * @covers \PHPExif\Adapter\AdapterAbstract::determinePropertySetter - */ - public function testDeterminePropertySetter() - { - $reflMethod = new \ReflectionMethod('\PHPExif\Adapter\Native', 'determinePropertySetter'); - $reflMethod->setAccessible(true); - - $result = $reflMethod->invoke( - $this->adapter, - 'foo' - ); - - $this->assertEquals('setFoo', $result); - } - - /** - * @group adapter - * @covers \PHPExif\Adapter\AdapterAbstract::getClassConstantsOfType - */ - public function testGetClassConstantsOfTypeAlwaysReturnsArray() - { - $result = $this->adapter->getClassConstantsOfType('sections'); - $this->assertInternalType('array', $result); - $result = $this->adapter->getClassConstantsOfType('foo'); - $this->assertInternalType('array', $result); - } - - /** - * @group adapter - * @covers \PHPExif\Adapter\AdapterAbstract::getClassConstantsOfType - */ - public function testGetClassConstantsOfTypeReturnsCorrectData() - { - $expected = array( - 'SECTIONS_AS_ARRAYS' => \PHPExif\Adapter\Native::SECTIONS_AS_ARRAYS, - 'SECTIONS_FLAT' => \PHPExif\Adapter\Native::SECTIONS_FLAT, - ); - $actual = $this->adapter->getClassConstantsOfType('sections'); - $this->assertEquals($expected, $actual); - } - - /** - * @group adapter - * @covers \PHPExif\Adapter\AdapterAbstract::toArray - */ - public function testToArrayReturnsPropertiesWithGetters() - { - $expected = array( - 'requiredSections', - 'includeThumbnail', - 'sectionsAsArrays', - ); - $result = $this->adapter->toArray(); - $actual = array_keys($result); - $this->assertEquals($expected, $actual); - } - - /** - * @group adapter - * @covers \PHPExif\Adapter\AdapterAbstract::toArray - */ - public function testToArrayOmmitsPropertiesWithoutGetters() - { - $expected = array( - 'iptcMapping', - ); - $result = $this->adapter->toArray(); - $actual = array_keys($result); - $diff = array_diff($expected, $actual); - $this->assertEquals($expected, $diff); - } - /** * @group adapter * @covers \PHPExif\Adapter\AdapterAbstract::setOptions @@ -127,7 +36,7 @@ public function testSetOptionsCorrectlySetsProperties() $this->adapter->setOptions($expected); foreach ($expected as $key => $value) { - $reflProp = new \ReflectionProperty('\PHPExif\Adapter\Native', $key); + $reflProp = new \ReflectionProperty('\\PHPExif\\Adapter\\Native', $key); $reflProp->setAccessible(true); $this->assertEquals($value, $reflProp->getValue($this->adapter)); } @@ -145,7 +54,7 @@ public function testSetOptionsIgnoresPropertiesWithoutSetters() $this->adapter->setOptions($expected); foreach ($expected as $key => $value) { - $reflProp = new \ReflectionProperty('\PHPExif\Adapter\Native', $key); + $reflProp = new \ReflectionProperty('\\PHPExif\\Adapter\\Native', $key); $reflProp->setAccessible(true); $this->assertNotEquals($value, $reflProp->getValue($this->adapter)); } @@ -166,7 +75,7 @@ public function testConstructorSetsOptions() $adapter = new \PHPExif\Adapter\Native($expected); foreach ($expected as $key => $value) { - $reflProp = new \ReflectionProperty('\PHPExif\Adapter\Native', $key); + $reflProp = new \ReflectionProperty('\\PHPExif\\Adapter\\Native', $key); $reflProp->setAccessible(true); $this->assertEquals($value, $reflProp->getValue($adapter)); } From bb6f4e263099e593bc723f287be6eeb42cb8446e Mon Sep 17 00:00:00 2001 From: Tom Van Herreweghe Date: Sun, 29 Mar 2015 19:28:50 +0200 Subject: [PATCH 04/38] Extracted mapping of ExifTool data to separate mapper & updated Exiftool adapter to use that mapper Signed-off-by: Tom Van Herreweghe --- lib/PHPExif/Adapter/Exiftool.php | 117 ++++--------------------- tests/PHPExif/Adapter/ExiftoolTest.php | 97 -------------------- 2 files changed, 17 insertions(+), 197 deletions(-) diff --git a/lib/PHPExif/Adapter/Exiftool.php b/lib/PHPExif/Adapter/Exiftool.php index 8e6bbe6..f7169ac 100644 --- a/lib/PHPExif/Adapter/Exiftool.php +++ b/lib/PHPExif/Adapter/Exiftool.php @@ -14,7 +14,6 @@ use PHPExif\Exif; use InvalidArgumentException; use RuntimeException; -use DateTime; /** * PHP Exif Exiftool Reader Adapter @@ -40,6 +39,11 @@ class Exiftool extends AdapterAbstract */ protected $numeric = true; + /** + * @var string + */ + protected $mapperClass = '\\PHPExif\\Mapper\\Exiftool'; + /** * Setter for the exiftool binary path * @@ -96,21 +100,25 @@ public function getToolPath() */ public function getExifFromFile($file) { - $gpsFormat = '%d deg %d\' %.4f\"'; - $result = $this->getCliOutput( sprintf( - '%1$s%3$s -j -c "%4$s" %2$s', + '%1$s%3$s -j %2$s', $this->getToolPath(), $file, - $this->numeric ? ' -n' : '', - $gpsFormat + $this->numeric ? ' -n' : '' ) ); $data = json_decode($result, true); - $mappedData = $this->mapData(reset($data)); - $exif = new Exif($mappedData); + + // map the data: + $mapper = $this->getMapper(); + $mappedData = $mapper->mapRawData(reset($data)); + + // hydrate a new Exif object + $exif = new Exif(); + $hydrator = $this->getHydrator(); + $hydrator->hydrate($exif, $mappedData); $exif->setRawData(reset($data)); return $exif; @@ -148,96 +156,5 @@ protected function getCliOutput($command) return $result; } - - /** - * Maps native data to Exif format - * - * @param array $source - * @return array - */ - public function mapData(array $source) - { - $focalLength = false; - if (isset($source['FocalLength'])) { - $focalLengthParts = explode(' ', $source['FocalLength']); - $focalLength = (int) reset($focalLengthParts); - } - - $exposureTime = false; - if (isset($source['ExposureTime'])) { - $exposureTime = '1/' . round(1 / $source['ExposureTime']); - } - - $caption = false; - if (isset($source['Caption'])) { - $caption = $source['Caption']; - } elseif (isset($source['Caption-Abstract'])) { - $caption = $source['Caption-Abstract']; - } - - $gpsLocation = false; - if (isset($source['GPSLatitudeRef']) && isset($source['GPSLongitudeRef'])) { - $latitude = $this->extractGPSCoordinates($source['GPSLatitude']); - $longitude = $this->extractGPSCoordinates($source['GPSLongitude']); - - if ($latitude !== false && $longitude !== false) { - $gpsLocation = sprintf( - '%s,%s', - (strtoupper($source['GPSLatitudeRef'][0]) === 'S' ? -1 : 1) * $latitude, - (strtoupper($source['GPSLongitudeRef'][0]) === 'W' ? -1 : 1) * $longitude - ); - } - } - - return array( - Exif::APERTURE => (!isset($source['Aperture'])) ? - false : sprintf('f/%01.1f', $source['Aperture']), - Exif::AUTHOR => (!isset($source['Artist'])) ? false : $source['Artist'], - Exif::CAMERA => (!isset($source['Model'])) ? false : $source['Model'], - Exif::CAPTION => $caption, - Exif::COLORSPACE => (!isset($source[Exif::COLORSPACE]) ? false : $source[Exif::COLORSPACE]), - Exif::COPYRIGHT => (!isset($source['Copyright'])) ? false : $source['Copyright'], - Exif::CREATION_DATE => (!isset($source['CreateDate'])) ? - false : DateTime::createFromFormat('Y:m:d H:i:s', $source['CreateDate']), - Exif::CREDIT => (!isset($source['Credit'])) ? false : $source['Credit'], - Exif::EXPOSURE => $exposureTime, - Exif::FILESIZE => (!isset($source[Exif::FILESIZE]) ? false : $source[Exif::FILESIZE]), - Exif::FOCAL_LENGTH => $focalLength, - Exif::FOCAL_DISTANCE => (!isset($source['ApproximateFocusDistance'])) ? - false : sprintf('%1$sm', $source['ApproximateFocusDistance']), - Exif::HEADLINE => (!isset($source['Headline'])) ? false : $source['Headline'], - Exif::HEIGHT => (!isset($source['ImageHeight'])) ? false : $source['ImageHeight'], - Exif::HORIZONTAL_RESOLUTION => (!isset($source['XResolution'])) ? false : $source['XResolution'], - Exif::ISO => (!isset($source['ISO'])) ? false : $source['ISO'], - Exif::JOB_TITLE => (!isset($source['JobTitle'])) ? false : $source['JobTitle'], - Exif::KEYWORDS => (!isset($source['Keywords'])) ? false : $source['Keywords'], - Exif::MIMETYPE => (!isset($source['MIMEType'])) ? false : $source['MIMEType'], - Exif::ORIENTATION => (!isset($source['Orientation'])) ? false : $source['Orientation'], - Exif::SOFTWARE => (!isset($source['Software'])) ? false : $source['Software'], - Exif::SOURCE => (!isset($source['Source'])) ? false : $source['Source'], - Exif::TITLE => (!isset($source['Title'])) ? false : $source['Title'], - Exif::VERTICAL_RESOLUTION => (!isset($source['YResolution'])) ? false : $source['YResolution'], - Exif::WIDTH => (!isset($source['ImageWidth'])) ? false : $source['ImageWidth'], - Exif::GPS => $gpsLocation, - ); - } - - /** - * Extract GPS coordinates from formatted string - * - * @param string $coordinates - * @return array - */ - protected function extractGPSCoordinates($coordinates) - { - if ($this->numeric === true) { - return abs((float) $coordinates); - } else { - if (!preg_match('!^([0-9.]+) deg ([0-9.]+)\' ([0-9.]+)"!', $coordinates, $matches)) { - return false; - } - - return intval($matches[1]) + (intval($matches[2]) / 60) + (floatval($matches[3]) / 3600); - } - } } + diff --git a/tests/PHPExif/Adapter/ExiftoolTest.php b/tests/PHPExif/Adapter/ExiftoolTest.php index 5e8783b..5d2b95c 100644 --- a/tests/PHPExif/Adapter/ExiftoolTest.php +++ b/tests/PHPExif/Adapter/ExiftoolTest.php @@ -73,103 +73,6 @@ public function testGetExifFromFile() $this->assertNotEmpty($result->getRawData()); } - /** - * @group exiftool - * @covers \PHPExif\Adapter\Exiftool::mapData - */ - public function testMapDataReturnsArray() - { - $this->assertInternalType('array', $this->adapter->mapData(array())); - } - - /** - * @group exiftool - * @covers \PHPExif\Adapter\Exiftool::mapData - */ - public function testMapDataReturnsArrayFalseValuesIfUndefined() - { - $result = $this->adapter->mapData(array()); - - foreach ($result as $value) { - $this->assertFalse($value); - } - } - - /** - * @group exiftool - * @covers \PHPExif\Adapter\Exiftool::mapData - */ - public function testMapDataResultHasAllKeys() - { - $reflClass = new \ReflectionClass('\PHPExif\Exif'); - $constants = $reflClass->getConstants(); - $result = $this->adapter->mapData(array()); - $keys = array_keys($result); - - $diff = array_diff($constants, $keys); - - $this->assertEquals(0, count($diff)); - } - - /** - * @group exiftool - * @covers \PHPExif\Adapter\Exiftool::mapData - */ - public function testMapDataFocalLengthIsCalculated() - { - $focalLength = '18 mm.'; - - $result = $this->adapter->mapData( - array( - 'FocalLength' => $focalLength, - ) - ); - - $this->assertEquals(18, $result[\PHPExif\Exif::FOCAL_LENGTH]); - } - - /** - * @group exiftool - * @covers \PHPExif\Adapter\Exiftool::setNumeric - * @covers \PHPExif\Adapter\Exiftool::mapData - * @covers \PHPExif\Adapter\Exiftool::extractGPSCoordinates - */ - public function testMapDataCreationDegGPSIsCalculated() - { - $this->adapter->setNumeric(false); - $result = $this->adapter->mapData( - array( - 'GPSLatitude' => '40 deg 20\' 0.42857" N', - 'GPSLatitudeRef' => 'North', - 'GPSLongitude' => '20 deg 10\' 2.33333" W', - 'GPSLongitudeRef' => 'West', - ) - ); - - $expected = '40.333452380556,-20.167314813889'; - $this->assertEquals($expected, $result[\PHPExif\Exif::GPS]); - } - - /** - * @group exiftool - * @covers \PHPExif\Adapter\Exiftool::mapData - * @covers \PHPExif\Adapter\Exiftool::extractGPSCoordinates - */ - public function testMapDataCreationNumericGPSIsCalculated() - { - $result = $this->adapter->mapData( - array( - 'GPSLatitude' => '40.333452381', - 'GPSLatitudeRef' => 'North', - 'GPSLongitude' => '20.167314814', - 'GPSLongitudeRef' => 'West', - ) - ); - - $expected = '40.333452381,-20.167314814'; - $this->assertEquals($expected, $result[\PHPExif\Exif::GPS]); - } - /** * @group exiftool * @covers \PHPExif\Adapter\Exiftool::getCliOutput From ae92380b78c452e8f706e085e34a213bc8aa7742 Mon Sep 17 00:00:00 2001 From: Tom Van Herreweghe Date: Sun, 29 Mar 2015 19:29:27 +0200 Subject: [PATCH 05/38] Extracted mapping of native data to separate mapper & updatd Native adapter to use that mapper Signed-off-by: Tom Van Herreweghe --- lib/PHPExif/Adapter/Native.php | 179 +++------------------------ tests/PHPExif/Adapter/NativeTest.php | 161 ------------------------ 2 files changed, 16 insertions(+), 324 deletions(-) diff --git a/lib/PHPExif/Adapter/Native.php b/lib/PHPExif/Adapter/Native.php index a7d6756..80fa630 100644 --- a/lib/PHPExif/Adapter/Native.php +++ b/lib/PHPExif/Adapter/Native.php @@ -60,6 +60,11 @@ class Native extends AdapterAbstract */ protected $sectionsAsArrays = self::SECTIONS_FLAT; + /** + * @var string + */ + protected $mapperClass = '\\PHPExif\\Mapper\\Native'; + /** * Contains the mapping of names to IPTC field numbers * @@ -189,8 +194,15 @@ public function getExifFromFile($file) $xmpData = $this->getIptcData($file); $data = array_merge($data, array(self::SECTION_IPTC => $xmpData)); - $mappedData = $this->mapData($data); - $exif = new Exif($mappedData); + + // map the data: + $mapper = $this->getMapper(); + $mappedData = $mapper->mapRawData($data); + + // hydrate a new Exif object + $exif = new Exif(); + $hydrator = $this->getHydrator(); + $hydrator->hydrate($exif, $mappedData); $exif->setRawData($data); return $exif; @@ -204,7 +216,7 @@ public function getExifFromFile($file) */ public function getIptcData($file) { - getimagesize($file, $info); + $size = getimagesize($file, $info); $arrData = array(); if (isset($info['APP13'])) { $iptc = iptcparse($info['APP13']); @@ -224,164 +236,5 @@ public function getIptcData($file) return $arrData; } - - /** - * Maps native data to Exif format - * - * @param array $source - * @return array - */ - public function mapData(array $source) - { - $focalLength = false; - if (isset($source['FocalLength'])) { - $parts = explode('/', $source['FocalLength']); - $focalLength = (int)reset($parts) / (int)end($parts); - } - - $horResolution = false; - if (isset($source['XResolution'])) { - $resolutionParts = explode('/', $source['XResolution']); - $horResolution = (int)reset($resolutionParts); - } - - $vertResolution = false; - if (isset($source['YResolution'])) { - $resolutionParts = explode('/', $source['YResolution']); - $vertResolution = (int)reset($resolutionParts); - } - - $exposureTime = false; - if (isset($source['ExposureTime'])) { - // normalize ExposureTime - // on one test image, it reported "10/300" instead of "1/30" - list($counter, $denominator) = explode('/', $source['ExposureTime']); - if (intval($counter) !== 1) { - $denominator /= $counter; - } - $exposureTime = '1/' . round($denominator); - } - - $gpsLocation = false; - if (isset($source['GPSLatitudeRef']) && isset($source['GPSLongitudeRef'])) { - $latitude = $this->extractGPSCoordinate($source['GPSLatitude']); - $longitude = $this->extractGPSCoordinate($source['GPSLongitude']); - - $gpsLocation = sprintf( - '%s,%s', - (strtoupper($source['GPSLatitudeRef'][0]) === 'S' ? -1 : 1) * $latitude, - (strtoupper($source['GPSLongitudeRef'][0]) === 'W' ? -1 : 1) * $longitude - ); - } - - return array( - Exif::APERTURE => (!isset($source[self::SECTION_COMPUTED]['ApertureFNumber'])) ? - false : $source[self::SECTION_COMPUTED]['ApertureFNumber'], - Exif::AUTHOR => (!isset($source['Artist'])) ? false : $source['Artist'], - Exif::CAMERA => (!isset($source['Model'])) ? false : $source['Model'], - Exif::CAPTION => (!isset($source[self::SECTION_IPTC]['caption'])) ? - false : $source[self::SECTION_IPTC]['caption'], - Exif::COLORSPACE => (!isset($source[Exif::COLORSPACE]) ? false : $source[Exif::COLORSPACE]), - Exif::COPYRIGHT => (!isset($source[self::SECTION_IPTC]['copyright'])) ? - false : $source[self::SECTION_IPTC]['copyright'], - Exif::CREATION_DATE => (!isset($source['DateTimeOriginal'])) ? - false : DateTime::createFromFormat('Y:m:d H:i:s', $source['DateTimeOriginal']), - Exif::CREDIT => (!isset($source[self::SECTION_IPTC]['credit'])) ? - false : $source[self::SECTION_IPTC]['credit'], - Exif::EXPOSURE => $exposureTime, - Exif::FILESIZE => (!isset($source[Exif::FILESIZE]) ? false : $source[Exif::FILESIZE]), - Exif::FOCAL_LENGTH => $focalLength, - Exif::FOCAL_DISTANCE => (!isset($source[self::SECTION_COMPUTED]['FocusDistance'])) ? - false : $source[self::SECTION_COMPUTED]['FocusDistance'], - Exif::HEADLINE => (!isset($source[self::SECTION_IPTC]['headline'])) ? - false : $source[self::SECTION_IPTC]['headline'], - Exif::HEIGHT => (!isset($source[self::SECTION_COMPUTED]['Height'])) ? - false : $source[self::SECTION_COMPUTED]['Height'], - Exif::HORIZONTAL_RESOLUTION => $horResolution, - Exif::ISO => (!isset($source['ISOSpeedRatings'])) ? false : $source['ISOSpeedRatings'], - Exif::JOB_TITLE => (!isset($source[self::SECTION_IPTC]['jobtitle'])) ? - false : $source[self::SECTION_IPTC]['jobtitle'], - Exif::KEYWORDS => (!isset($source[self::SECTION_IPTC]['keywords'])) ? - false : $source[self::SECTION_IPTC]['keywords'], - Exif::MIMETYPE => (!isset($source[Exif::MIMETYPE]) ? false : $source[Exif::MIMETYPE]), - Exif::ORIENTATION => (!isset($source[Exif::ORIENTATION]) ? false : $source[Exif::ORIENTATION]), - Exif::SOFTWARE => (!isset($source['Software'])) ? false : trim($source['Software']), - Exif::SOURCE => (!isset($source[self::SECTION_IPTC]['source'])) ? - false : $source[self::SECTION_IPTC]['source'], - Exif::TITLE => (!isset($source[self::SECTION_IPTC]['title'])) ? - false : $source[self::SECTION_IPTC]['title'], - Exif::VERTICAL_RESOLUTION => $vertResolution, - Exif::WIDTH => (!isset($source[self::SECTION_COMPUTED]['Width'])) ? - false : $source[self::SECTION_COMPUTED]['Width'], - Exif::GPS => $gpsLocation, - ); - - $arrMapping = array( - array( - Exif::AUTHOR => 'Artist', - Exif::CAMERA => 'Model', - Exif::EXPOSURE => 'ExposureTime', - Exif::ISO => 'ISOSpeedRatings', - Exif::SOFTWARE => 'Software', - ), - self::SECTION_COMPUTED => array( - Exif::APERTURE => 'ApertureFNumber', - Exif::FOCAL_DISTANCE => 'FocusDistance', - Exif::HEIGHT => 'Height', - Exif::WIDTH => 'Width', - ), - self::SECTION_IPTC => array( - Exif::CAPTION => 'caption', - Exif::COPYRIGHT => 'copyright', - Exif::CREDIT => 'credit', - Exif::HEADLINE => 'headline', - Exif::JOB_TITLE => 'jobtitle', - Exif::KEYWORDS => 'keywords', - Exif::SOURCE => 'source', - Exif::TITLE => 'title', - ), - ); - - foreach ($arrMapping as $key => $arrFields) { - if (array_key_exists($key, $source)) { - $arrSource = $source[$key]; - } else { - $arrSource = $source; - } - - foreach ($arrFields as $mappedField => $field) { - if (isset($arrSource[$field])) { - $mappedData[$mappedField] = $arrSource[$field]; - } - } - } - - return $mappedData; - } - - /** - * Extract GPS coordinates from components array - * - * @param array $components - * @return float - */ - protected function extractGPSCoordinate(array $components) - { - $components = array_map(array($this, 'normalizeGPSComponent'), $components); - - return intval($components[0]) + (intval($components[1]) / 60) + (floatval($components[2]) / 3600); - } - - /** - * Normalize GPS coordinates components - * - * @param mixed $component - * @return int|float - */ - protected function normalizeGPSComponent($component) - { - $parts = explode('/', $component); - - return count($parts) === 1 ? $parts[0] : (int) reset($parts) / (int) end($parts); - } } + diff --git a/tests/PHPExif/Adapter/NativeTest.php b/tests/PHPExif/Adapter/NativeTest.php index 381f506..4675b3a 100755 --- a/tests/PHPExif/Adapter/NativeTest.php +++ b/tests/PHPExif/Adapter/NativeTest.php @@ -179,165 +179,4 @@ public function testGetSectionsAsArrayFromProperty() $this->assertEquals(\PHPExif\Adapter\Native::SECTIONS_AS_ARRAYS, $this->adapter->getSectionsAsArrays()); } - - /** - * @group native - * @covers \PHPExif\Adapter\Native::mapData - */ - public function testMapDataReturnsArray() - { - $this->assertInternalType('array', $this->adapter->mapData(array())); - } - - /** - * @group native - * @covers \PHPExif\Adapter\Native::mapData - */ - public function testMapDataMapsFirstLevel() - { - $result = $this->adapter->mapData( - array( - 'Software' => 'Foo', - ) - ); - $this->assertEquals( - 'Foo', - $result[\PHPExif\Exif::SOFTWARE] - ); - } - - /** - * @group native - * @covers \PHPExif\Adapter\Native::mapData - */ - public function testMapDataMapsSecondLevel() - { - $result = $this->adapter->mapData( - array( - \PHPExif\Adapter\Native::SECTION_COMPUTED => array( - 'Height' => '1500' - ) - ) - ); - $this->assertEquals( - 1500, - $result[\PHPExif\Exif::HEIGHT] - ); - } - - /** - * @group native - * @covers \PHPExif\Adapter\Native::mapData - */ - public function testMapDataReturnsArrayFalseValuesIfUndefined() - { - $result = $this->adapter->mapData(array()); - - foreach ($result as $key => $value) { - $this->assertFalse($value); - } - } - - /** - * @group native - * @covers \PHPExif\Adapter\Native::mapData - */ - public function testMapDataResultHasAllKeys() - { - $reflClass = new \ReflectionClass('\PHPExif\Exif'); - $constants = $reflClass->getConstants(); - $result = $this->adapter->mapData(array()); - $keys = array_keys($result); - - $diff = array_diff($constants, $keys); - - $this->assertEquals(0, count($diff)); - } - - /** - * @group native - * @covers \PHPExif\Adapter\Native::mapData - */ - public function testMapDataFocalLengthIsCalculated() - { - $focalLength = '1/320'; - - $result = $this->adapter->mapData( - array( - 'FocalLength' => $focalLength, - ) - ); - - $this->assertEquals(1/320, $result[\PHPExif\Exif::FOCAL_LENGTH]); - } - - /** - * @group native - * @covers \PHPExif\Adapter\Native::mapData - */ - public function testMapDataHorizontalResolutionIsCalculated() - { - $xRes = '240/1'; - - $result = $this->adapter->mapData( - array( - 'XResolution' => $xRes, - ) - ); - - $this->assertEquals(240, $result[\PHPExif\Exif::HORIZONTAL_RESOLUTION]); - } - - /** - * @group native - * @covers \PHPExif\Adapter\Native::mapData - */ - public function testMapDataVerticalResolutionIsCalculated() - { - $yRes = '240/1'; - - $result = $this->adapter->mapData( - array( - 'YResolution' => $yRes, - ) - ); - - $this->assertEquals(240, $result[\PHPExif\Exif::VERTICAL_RESOLUTION]); - } - - /** - * @group native-curr - * @covers \PHPExif\Adapter\Native::mapData - */ - public function testMapDataCreationDateIsConvertedToDatetime() - { - $result = $this->adapter->mapData( - array( - 'DateTimeOriginal' => '2013:06:30 12:34:56', - ) - ); - - $this->assertInstanceOf('DateTime', $result[\PHPExif\Exif::CREATION_DATE]); - } - - /** - * @group native - * @covers \PHPExif\Adapter\Native::mapData - * @covers \PHPExif\Adapter\Native::extractGPSCoordinate - * @covers \PHPExif\Adapter\Native::normalizeGPSComponent - */ - public function testMapDataCreationGPSIsCalculated() - { - $result = $this->adapter->mapData( - array( - 'GPSLatitude' => array('40/1', '20/1', '15/35'), - 'GPSLatitudeRef' => 'N', - 'GPSLongitude' => array('20/1', '10/1', '35/15'), - 'GPSLongitudeRef' => 'W', - ) - ); - - $expected = '40.333452380952,-20.167314814815'; - $this->assertEquals($expected, $result[\PHPExif\Exif::GPS]); - } } From 0ba62768f73dfbea36276b696b036d407b345b64 Mon Sep 17 00:00:00 2001 From: Tom Van Herreweghe Date: Sun, 29 Mar 2015 21:52:22 +0200 Subject: [PATCH 06/38] Bugfixed some small inconsistencies Signed-off-by: Tom Van Herreweghe --- lib/PHPExif/Mapper/Exiftool.php | 6 +++--- lib/PHPExif/Mapper/Native.php | 31 +++++++++++++++++++++++++++++-- 2 files changed, 32 insertions(+), 5 deletions(-) diff --git a/lib/PHPExif/Mapper/Exiftool.php b/lib/PHPExif/Mapper/Exiftool.php index 27dbbe2..5c21466 100644 --- a/lib/PHPExif/Mapper/Exiftool.php +++ b/lib/PHPExif/Mapper/Exiftool.php @@ -31,7 +31,7 @@ class Exiftool implements MapperInterface const CAPTIONABSTRACT = 'Caption-Abstract'; const COLORSPACE = 'ColorSpace'; const COPYRIGHT = 'Copyright'; - const CREATIONDATE = 'CreationDate'; + const CREATEDATE = 'CreateDate'; const CREDIT = 'Credit'; const EXPOSURETIME = 'ExposureTime'; const FILESIZE = 'FileSize'; @@ -65,7 +65,7 @@ class Exiftool implements MapperInterface self::CAPTIONABSTRACT => Exif::CAPTION, self::COLORSPACE => Exif::COLORSPACE, self::COPYRIGHT => Exif::COPYRIGHT, - self::CREATIONDATE => Exif::CREATION_DATE, + self::CREATEDATE => Exif::CREATION_DATE, self::CREDIT => Exif::CREDIT, self::EXPOSURETIME => Exif::EXPOSURE, self::FILESIZE => Exif::FILESIZE, @@ -112,7 +112,7 @@ public function mapRawData(array $data) case self::APPROXIMATEFOCUSDISTANCE: $value = sprintf('%1$sm', $value); break; - case self::CREATIONDATE: + case self::CREATEDATE: $value = DateTime::createFromFormat('Y:m:d H:i:s', $value); break; case self::EXPOSURETIME: diff --git a/lib/PHPExif/Mapper/Native.php b/lib/PHPExif/Mapper/Native.php index ac36580..b8502cb 100644 --- a/lib/PHPExif/Mapper/Native.php +++ b/lib/PHPExif/Mapper/Native.php @@ -40,7 +40,7 @@ class Native implements MapperInterface const ISOSPEEDRATINGS = 'ISOSpeedRatings'; const JOBTITLE = 'jobtitle'; const KEYWORDS = 'keywords'; - const MIMETYPE = 'MIMEType'; + const MIMETYPE = 'MimeType'; const MODEL = 'Model'; const ORIENTATION = 'Orientation'; const SOFTWARE = 'Software'; @@ -59,6 +59,22 @@ class Native implements MapperInterface const SECTION_ALL = 'ANY_TAG'; const SECTION_IPTC = 'IPTC'; + /** + * A list of section names + * + * @var array + */ + protected $sections = array( + self::SECTION_FILE, + self::SECTION_COMPUTED, + self::SECTION_IFD0, + self::SECTION_THUMBNAIL, + self::SECTION_COMMENT, + self::SECTION_EXIF, + self::SECTION_ALL, + self::SECTION_IPTC, + ); + /** * Maps the ExifTool fields to the fields of * the \PHPExif\Exif class @@ -108,7 +124,7 @@ public function mapRawData(array $data) { $mappedData = array(); foreach ($data as $field => $value) { - if (is_string($field) && is_array($value)) { + if ($this->isSection($field) && is_array($value)) { $subData = $this->mapRawData($value); $mappedData = array_merge($mappedData, $subData); @@ -153,5 +169,16 @@ public function mapRawData(array $data) return $mappedData; } + + /** + * Determines if given field is a section + * + * @param string $field + * @return bool + */ + protected function isSection($field) + { + return (in_array($field, $this->sections)); + } } From fb7763f5f478e0a1d66f975b1ceb929f33cd2189 Mon Sep 17 00:00:00 2001 From: Tom Van Herreweghe Date: Sun, 29 Mar 2015 21:52:37 +0200 Subject: [PATCH 07/38] Added mutators to Exif class & updated unit tests Signed-off-by: Tom Van Herreweghe --- lib/PHPExif/Exif.php | 339 +++++++++++++++++++++++++++++++++++-- tests/PHPExif/ExifTest.php | 4 +- 2 files changed, 328 insertions(+), 15 deletions(-) diff --git a/lib/PHPExif/Exif.php b/lib/PHPExif/Exif.php index 4f39c6d..8eddff5 100755 --- a/lib/PHPExif/Exif.php +++ b/lib/PHPExif/Exif.php @@ -47,7 +47,6 @@ class Exif const TITLE = 'title'; const VERTICAL_RESOLUTION = 'verticalResolution'; const WIDTH = 'width'; - const GPS = 'gps'; /** * The mapped EXIF data @@ -133,6 +132,19 @@ public function getAperture() return $this->data[self::APERTURE]; } + /** + * Sets the Aperture F-number + * + * @param string $value + * @return \PHPExif\Exif + */ + public function setAperture($value) + { + $this->data[self::APERTURE] = $value; + + return $this; + } + /** * Returns the Author * @@ -147,6 +159,19 @@ public function getAuthor() return $this->data[self::AUTHOR]; } + /** + * Sets the Author + * + * @param string $value + * @return \PHPExif\Exif + */ + public function setAuthor($value) + { + $this->data[self::AUTHOR] = $value; + + return $this; + } + /** * Returns the Headline * @@ -161,6 +186,19 @@ public function getHeadline() return $this->data[self::HEADLINE]; } + /** + * Sets the Headline + * + * @param string $value + * @return \PHPExif\Exif + */ + public function setHeadline($value) + { + $this->data[self::HEADLINE] = $value; + + return $this; + } + /** * Returns the Credit * @@ -175,6 +213,19 @@ public function getCredit() return $this->data[self::CREDIT]; } + /** + * Sets the Credit + * + * @param string $value + * @return \PHPExif\Exif + */ + public function setCredit($value) + { + $this->data[self::CREDIT] = $value; + + return $this; + } + /** * Returns the source * @@ -189,6 +240,19 @@ public function getSource() return $this->data[self::SOURCE]; } + /** + * Sets the Source + * + * @param string $value + * @return \PHPExif\Exif + */ + public function setSource($value) + { + $this->data[self::SOURCE] = $value; + + return $this; + } + /** * Returns the Jobtitle * @@ -203,6 +267,19 @@ public function getJobtitle() return $this->data[self::JOB_TITLE]; } + /** + * Sets the Jobtitle + * + * @param string $value + * @return \PHPExif\Exif + */ + public function setJobtitle($value) + { + $this->data[self::JOB_TITLE] = $value; + + return $this; + } + /** * Returns the ISO speed * @@ -217,6 +294,19 @@ public function getIso() return $this->data[self::ISO]; } + /** + * Sets the ISO + * + * @param int $value + * @return \PHPExif\Exif + */ + public function setIso($value) + { + $this->data[self::ISO] = $value; + + return $this; + } + /** * Returns the Exposure * @@ -231,6 +321,19 @@ public function getExposure() return $this->data[self::EXPOSURE]; } + /** + * Sets the Exposure + * + * @param string $value + * @return \PHPExif\Exif + */ + public function setExposure($value) + { + $this->data[self::EXPOSURE] = $value; + + return $this; + } + /** * Returns the Exposure * @@ -261,6 +364,19 @@ public function getFocusDistance() return $this->data[self::FOCAL_DISTANCE]; } + /** + * Sets the focus distance + * + * @param string $value + * @return \PHPExif\Exif + */ + public function setFocusDistance($value) + { + $this->data[self::FOCAL_DISTANCE] = $value; + + return $this; + } + /** * Returns the width in pixels, if it exists * @@ -275,6 +391,19 @@ public function getWidth() return $this->data[self::WIDTH]; } + /** + * Sets the width + * + * @param int $value + * @return \PHPExif\Exif + */ + public function setWidth($value) + { + $this->data[self::WIDTH] = $value; + + return $this; + } + /** * Returns the height in pixels, if it exists * @@ -289,6 +418,19 @@ public function getHeight() return $this->data[self::HEIGHT]; } + /** + * Sets the height + * + * @param int $value + * @return \PHPExif\Exif + */ + public function setHeight($value) + { + $this->data[self::HEIGHT] = $value; + + return $this; + } + /** * Returns the title, if it exists * @@ -303,6 +445,19 @@ public function getTitle() return $this->data[self::TITLE]; } + /** + * Sets the title + * + * @param string $value + * @return \PHPExif\Exif + */ + public function setTitle($value) + { + $this->data[self::TITLE] = $value; + + return $this; + } + /** * Returns the caption, if it exists * @@ -317,6 +472,19 @@ public function getCaption() return $this->data[self::CAPTION]; } + /** + * Sets the caption + * + * @param string $value + * @return \PHPExif\Exif + */ + public function setCaption($value) + { + $this->data[self::CAPTION] = $value; + + return $this; + } + /** * Returns the copyright, if it exists * @@ -331,6 +499,19 @@ public function getCopyright() return $this->data[self::COPYRIGHT]; } + /** + * Sets the copyright + * + * @param string $value + * @return \PHPExif\Exif + */ + public function setCopyright($value) + { + $this->data[self::COPYRIGHT] = $value; + + return $this; + } + /** * Returns the keywords, if they exists * @@ -345,6 +526,19 @@ public function getKeywords() return $this->data[self::KEYWORDS]; } + /** + * Sets the keywords + * + * @param array $value + * @return \PHPExif\Exif + */ + public function setKeywords($value) + { + $this->data[self::KEYWORDS] = $value; + + return $this; + } + /** * Returns the camera, if it exists * @@ -359,6 +553,19 @@ public function getCamera() return $this->data[self::CAMERA]; } + /** + * Sets the camera + * + * @param string $value + * @return \PHPExif\Exif + */ + public function setCamera($value) + { + $this->data[self::CAMERA] = $value; + + return $this; + } + /** * Returns the horizontal resolution in DPI, if it exists * @@ -373,6 +580,19 @@ public function getHorizontalResolution() return $this->data[self::HORIZONTAL_RESOLUTION]; } + /** + * Sets the horizontal resolution in DPI + * + * @param int $value + * @return \PHPExif\Exif + */ + public function setHorizontalResolution($value) + { + $this->data[self::HORIZONTAL_RESOLUTION] = $value; + + return $this; + } + /** * Returns the vertical resolution in DPI, if it exists * @@ -387,6 +607,19 @@ public function getVerticalResolution() return $this->data[self::VERTICAL_RESOLUTION]; } + /** + * Sets the vertical resolution in DPI + * + * @param int $value + * @return \PHPExif\Exif + */ + public function setVerticalResolution($value) + { + $this->data[self::VERTICAL_RESOLUTION] = $value; + + return $this; + } + /** * Returns the software, if it exists * @@ -401,6 +634,19 @@ public function getSoftware() return $this->data[self::SOFTWARE]; } + /** + * Sets the software + * + * @param string $value + * @return \PHPExif\Exif + */ + public function setSoftware($value) + { + $this->data[self::SOFTWARE] = trim($value); + + return $this; + } + /** * Returns the focal length in mm, if it exists * @@ -415,6 +661,19 @@ public function getFocalLength() return $this->data[self::FOCAL_LENGTH]; } + /** + * Sets the focal length in mm + * + * @param float $value + * @return \PHPExif\Exif + */ + public function setFocalLength($value) + { + $this->data[self::FOCAL_LENGTH] = $value; + + return $this; + } + /** * Returns the creation datetime, if it exists * @@ -429,6 +688,19 @@ public function getCreationDate() return $this->data[self::CREATION_DATE]; } + /** + * Sets the creation datetime + * + * @param \DateTime $value + * @return \PHPExif\Exif + */ + public function setCreationDate(\DateTime $value) + { + $this->data[self::CREATION_DATE] = $value; + + return $this; + } + /** * Returns the colorspace, if it exists * @@ -439,10 +711,23 @@ public function getColorSpace() if (!isset($this->data[self::COLORSPACE])) { return false; } - + return $this->data[self::COLORSPACE]; } + /** + * Sets the colorspace + * + * @param string $value + * @return \PHPExif\Exif + */ + public function setColorSpace($value) + { + $this->data[self::COLORSPACE] = $value; + + return $this; + } + /** * Returns the mimetype, if it exists * @@ -453,28 +738,54 @@ public function getMimeType() if (!isset($this->data[self::MIMETYPE])) { return false; } - + return $this->data[self::MIMETYPE]; } /** - * Returns the filesize, if it exists + * Sets the mimetype * - * @return integer + * @param string $value + * @return \PHPExif\Exif + */ + public function setMimeType($value) + { + $this->data[self::MIMETYPE] = $value; + + return $this; + } + + /** + * Returns the filesize, if it exists + * + * @return int */ public function getFileSize() { if (!isset($this->data[self::FILESIZE])) { return false; } - + return $this->data[self::FILESIZE]; } + /** + * Sets the filesize + * + * @param int $value + * @return \PHPExif\Exif + */ + public function setFileSize($value) + { + $this->data[self::FILESIZE] = $value; + + return $this; + } + /** * Returns the orientation, if it exists * - * @return integer + * @return int */ public function getOrientation() { @@ -486,16 +797,16 @@ public function getOrientation() } /** - * Returns GPS coordinates, if it exists + * Sets the orientation * - * @return array|boolean + * @param int $value + * @return \PHPExif\Exif */ - public function getGPS() + public function setOrientation($value) { - if (!isset($this->data[self::GPS])) { - return false; - } + $this->data[self::ORIENTATION] = $value; - return $this->data[self::GPS]; + return $this; } } + diff --git a/tests/PHPExif/ExifTest.php b/tests/PHPExif/ExifTest.php index 8f51f21..e5fc29a 100755 --- a/tests/PHPExif/ExifTest.php +++ b/tests/PHPExif/ExifTest.php @@ -460,6 +460,8 @@ public function testGetGPS() /** * Test that the values returned by both adapters are equal + * + * @group consistency */ public function testAdapterConsistency() { @@ -480,7 +482,7 @@ public function testAdapterConsistency() // find all Getter methods on the results and compare its output foreach ($methods as $method) { $name = $method->getName(); - if (strpos($name, 'get') !== 0 || $name == 'getRawData') { + if (strpos($name, 'get') !== 0 || $name == 'getRawData' || $name == 'getData') { continue; } $this->assertEquals( From ec812d9e1ff4a1c4e9116be457fc3466f6dcd0da Mon Sep 17 00:00:00 2001 From: Tom Van Herreweghe Date: Sun, 29 Mar 2015 21:57:50 +0200 Subject: [PATCH 08/38] Removed blank lines to conform to PSR2 Signed-off-by: Tom Van Herreweghe --- lib/PHPExif/Adapter/Exiftool.php | 1 - lib/PHPExif/Adapter/Native.php | 1 - lib/PHPExif/Exif.php | 1 - lib/PHPExif/Hydrator/HydratorInterface.php | 1 - lib/PHPExif/Hydrator/Mutator.php | 1 - lib/PHPExif/Mapper/Exiftool.php | 1 - lib/PHPExif/Mapper/MapperInterface.php | 1 - lib/PHPExif/Mapper/Native.php | 1 - 8 files changed, 8 deletions(-) diff --git a/lib/PHPExif/Adapter/Exiftool.php b/lib/PHPExif/Adapter/Exiftool.php index f7169ac..d8f715b 100644 --- a/lib/PHPExif/Adapter/Exiftool.php +++ b/lib/PHPExif/Adapter/Exiftool.php @@ -157,4 +157,3 @@ protected function getCliOutput($command) return $result; } } - diff --git a/lib/PHPExif/Adapter/Native.php b/lib/PHPExif/Adapter/Native.php index 80fa630..862aa5a 100644 --- a/lib/PHPExif/Adapter/Native.php +++ b/lib/PHPExif/Adapter/Native.php @@ -237,4 +237,3 @@ public function getIptcData($file) return $arrData; } } - diff --git a/lib/PHPExif/Exif.php b/lib/PHPExif/Exif.php index 8eddff5..bbf1bea 100755 --- a/lib/PHPExif/Exif.php +++ b/lib/PHPExif/Exif.php @@ -809,4 +809,3 @@ public function setOrientation($value) return $this; } } - diff --git a/lib/PHPExif/Hydrator/HydratorInterface.php b/lib/PHPExif/Hydrator/HydratorInterface.php index 8f81bdd..fd8b797 100644 --- a/lib/PHPExif/Hydrator/HydratorInterface.php +++ b/lib/PHPExif/Hydrator/HydratorInterface.php @@ -30,4 +30,3 @@ interface HydratorInterface */ public function hydrate($object, array $data); } - diff --git a/lib/PHPExif/Hydrator/Mutator.php b/lib/PHPExif/Hydrator/Mutator.php index 52559d1..164d57c 100644 --- a/lib/PHPExif/Hydrator/Mutator.php +++ b/lib/PHPExif/Hydrator/Mutator.php @@ -53,4 +53,3 @@ protected function determineMutator($property) return $method; } } - diff --git a/lib/PHPExif/Mapper/Exiftool.php b/lib/PHPExif/Mapper/Exiftool.php index 5c21466..3baa68a 100644 --- a/lib/PHPExif/Mapper/Exiftool.php +++ b/lib/PHPExif/Mapper/Exiftool.php @@ -131,4 +131,3 @@ public function mapRawData(array $data) return $mappedData; } } - diff --git a/lib/PHPExif/Mapper/MapperInterface.php b/lib/PHPExif/Mapper/MapperInterface.php index 234ca06..0479740 100644 --- a/lib/PHPExif/Mapper/MapperInterface.php +++ b/lib/PHPExif/Mapper/MapperInterface.php @@ -30,4 +30,3 @@ interface MapperInterface */ public function mapRawData(array $data); } - diff --git a/lib/PHPExif/Mapper/Native.php b/lib/PHPExif/Mapper/Native.php index b8502cb..689c983 100644 --- a/lib/PHPExif/Mapper/Native.php +++ b/lib/PHPExif/Mapper/Native.php @@ -181,4 +181,3 @@ protected function isSection($field) return (in_array($field, $this->sections)); } } - From 3c36d12ebb8dd2b412c7f0f869fa0a7113d33cdc Mon Sep 17 00:00:00 2001 From: Tom Van Herreweghe Date: Mon, 30 Mar 2015 13:35:22 +0200 Subject: [PATCH 09/38] Add unit test for Exiftool::setNumeric Signed-off-by: Tom Van Herreweghe --- tests/PHPExif/Adapter/ExiftoolTest.php | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/tests/PHPExif/Adapter/ExiftoolTest.php b/tests/PHPExif/Adapter/ExiftoolTest.php index 5d2b95c..7211f37 100644 --- a/tests/PHPExif/Adapter/ExiftoolTest.php +++ b/tests/PHPExif/Adapter/ExiftoolTest.php @@ -60,6 +60,21 @@ public function testGetToolPathLazyLoadsPath() $this->assertInternalType('string', $this->adapter->getToolPath()); } + /** + * @group exiftool + * @covers \PHPExif\Adapter\Exiftool::setNumeric + */ + public function testSetNumericInProperty() + { + $reflProperty = new \ReflectionProperty('\PHPExif\Adapter\Exiftool', 'numeric'); + $reflProperty->setAccessible(true); + + $expected = true; + $this->adapter->setNumeric($expected); + + $this->assertEquals($expected, $reflProperty->getValue($this->adapter)); + } + /** * @group exiftool * @covers \PHPExif\Adapter\Exiftool::getExifFromFile From 2daf6e169bd3b8bfa9f1562cc6e9f3ed877ecd7d Mon Sep 17 00:00:00 2001 From: Tom Van Herreweghe Date: Mon, 30 Mar 2015 13:47:59 +0200 Subject: [PATCH 10/38] Add extra unit tests for Reader class Signed-off-by: Tom Van Herreweghe --- tests/PHPExif/Reader/ReaderTest.php | 40 +++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/tests/PHPExif/Reader/ReaderTest.php b/tests/PHPExif/Reader/ReaderTest.php index af546c4..4d62602 100644 --- a/tests/PHPExif/Reader/ReaderTest.php +++ b/tests/PHPExif/Reader/ReaderTest.php @@ -45,6 +45,20 @@ public function testGetAdapterFromProperty() $this->assertSame($mock, $this->reader->getAdapter()); } + /** + * @group reader + * @covers \PHPExif\Reader\Reader::getAdapter + * @expectedException \PHPExif\Adapter\NoAdapterException + */ + public function testGetAdapterThrowsExceptionWhenNoAdapterIsSet() + { + $reflProperty = new \ReflectionProperty('\PHPExif\Reader\Reader', 'adapter'); + $reflProperty->setAccessible(true); + $reflProperty->setValue($this->reader, null); + + $this->reader->getAdapter(); + } + /** * @group reader * @covers \PHPExif\Reader\Reader::read @@ -112,4 +126,30 @@ public function testFactoryAdapterTypeExiftool() $this->assertInstanceOf('\PHPExif\Adapter\Exiftool', $adapter); } + /** + * @group reader + * @covers \PHPExif\Reader\Reader::getExifFromFile + */ + public function testGetExifFromFileCallsReadMethod() + { + $mock = $this->getMock( + '\\PHPExif\\Reader\\Reader', + array('read'), + array(), + '', + false + ); + + $expected = '/foo/bar/baz'; + $expectedResult = 'test'; + + $mock->expects($this->once()) + ->method('read') + ->with($this->equalTo($expected)) + ->will($this->returnValue($expectedResult)); + + $result = $mock->getExifFromFile($expected); + $this->assertEquals($expectedResult, $result); + } } + From a288667ae656b27674d9fb2163631c47af2b95ea Mon Sep 17 00:00:00 2001 From: Tom Van Herreweghe Date: Mon, 30 Mar 2015 14:56:09 +0200 Subject: [PATCH 11/38] Add some tests for Exif class Signed-off-by: Tom Van Herreweghe --- .travis.yml | 2 +- tests/PHPExif/ExifTest.php | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index b6272df..90c6091 100755 --- a/.travis.yml +++ b/.travis.yml @@ -13,7 +13,7 @@ matrix: script: - mkdir -p build/logs - php vendor/bin/phpunit -c phpunit.xml.dist - - ./vendor/bin/phpunit --coverage-clover ./build/logs/clover.xml + - ./vendor/bin/phpunit --coverage-clover ./build/logs/clover.xml --strict-coverage - ./vendor/bin/phpcs --standard=PSR2 ./lib/ before_script: diff --git a/tests/PHPExif/ExifTest.php b/tests/PHPExif/ExifTest.php index e5fc29a..51de23f 100755 --- a/tests/PHPExif/ExifTest.php +++ b/tests/PHPExif/ExifTest.php @@ -133,6 +133,8 @@ public function providerUndefinedPropertiesReturnFalse() array('getCredit'), array('getSource'), array('getJobtitle'), + array('getMimeType'), + array('getFileSize'), ); } @@ -494,3 +496,4 @@ public function testAdapterConsistency() } } } + From d16cacb469eae0e48d58437da1717f55172ae60a Mon Sep 17 00:00:00 2001 From: Tom Van Herreweghe Date: Mon, 30 Mar 2015 15:01:45 +0200 Subject: [PATCH 12/38] Remove strict coverage option Signed-off-by: Tom Van Herreweghe --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 90c6091..b6272df 100755 --- a/.travis.yml +++ b/.travis.yml @@ -13,7 +13,7 @@ matrix: script: - mkdir -p build/logs - php vendor/bin/phpunit -c phpunit.xml.dist - - ./vendor/bin/phpunit --coverage-clover ./build/logs/clover.xml --strict-coverage + - ./vendor/bin/phpunit --coverage-clover ./build/logs/clover.xml - ./vendor/bin/phpcs --standard=PSR2 ./lib/ before_script: From 4e0ee69d491d35ce20ef29899b4ab9334431cf98 Mon Sep 17 00:00:00 2001 From: Tom Van Herreweghe Date: Mon, 30 Mar 2015 15:44:24 +0200 Subject: [PATCH 13/38] Made coverage more explicit Signed-off-by: Tom Van Herreweghe --- tests/PHPExif/Adapter/AdapterAbstractTest.php | 4 +++- tests/PHPExif/Adapter/ExiftoolTest.php | 3 +++ tests/PHPExif/Adapter/NativeTest.php | 3 +++ tests/PHPExif/ExifTest.php | 4 +++- tests/PHPExif/Reader/ReaderTest.php | 3 +++ 5 files changed, 15 insertions(+), 2 deletions(-) diff --git a/tests/PHPExif/Adapter/AdapterAbstractTest.php b/tests/PHPExif/Adapter/AdapterAbstractTest.php index fd52e37..7b30d48 100644 --- a/tests/PHPExif/Adapter/AdapterAbstractTest.php +++ b/tests/PHPExif/Adapter/AdapterAbstractTest.php @@ -1,5 +1,7 @@ + */ class AdapterAbstractTest extends \PHPUnit_Framework_TestCase { /** diff --git a/tests/PHPExif/Adapter/ExiftoolTest.php b/tests/PHPExif/Adapter/ExiftoolTest.php index 7211f37..71abd2a 100644 --- a/tests/PHPExif/Adapter/ExiftoolTest.php +++ b/tests/PHPExif/Adapter/ExiftoolTest.php @@ -1,4 +1,7 @@ + */ class ExiftoolTest extends \PHPUnit_Framework_TestCase { /** diff --git a/tests/PHPExif/Adapter/NativeTest.php b/tests/PHPExif/Adapter/NativeTest.php index 4675b3a..7dd86b6 100755 --- a/tests/PHPExif/Adapter/NativeTest.php +++ b/tests/PHPExif/Adapter/NativeTest.php @@ -1,4 +1,7 @@ + */ class NativeTest extends \PHPUnit_Framework_TestCase { /** diff --git a/tests/PHPExif/ExifTest.php b/tests/PHPExif/ExifTest.php index 51de23f..bfee7f5 100755 --- a/tests/PHPExif/ExifTest.php +++ b/tests/PHPExif/ExifTest.php @@ -1,5 +1,7 @@ + */ class ExifTest extends \PHPUnit_Framework_TestCase { /** diff --git a/tests/PHPExif/Reader/ReaderTest.php b/tests/PHPExif/Reader/ReaderTest.php index 4d62602..7e8c0c0 100644 --- a/tests/PHPExif/Reader/ReaderTest.php +++ b/tests/PHPExif/Reader/ReaderTest.php @@ -1,4 +1,7 @@ + */ class ReaderTest extends \PHPUnit_Framework_TestCase { /** From 5eb8ca59b0689837e7dfe1fedb4ce0a8e32a163e Mon Sep 17 00:00:00 2001 From: Tom Van Herreweghe Date: Mon, 30 Mar 2015 16:22:04 +0200 Subject: [PATCH 14/38] Add @covers annotation for Exif tests Signed-off-by: Tom Van Herreweghe --- tests/PHPExif/ExifTest.php | 55 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/tests/PHPExif/ExifTest.php b/tests/PHPExif/ExifTest.php index bfee7f5..7e8d420 100755 --- a/tests/PHPExif/ExifTest.php +++ b/tests/PHPExif/ExifTest.php @@ -19,6 +19,7 @@ public function setUp() /** * @group exif + * @covers \PHPExif\Exif::__construct */ public function testConstructorCallsSetData() { @@ -44,6 +45,7 @@ public function testConstructorCallsSetData() /** * @group exif + * @covers \PHPExif\Exif::getRawData */ public function testGetRawData() { @@ -55,6 +57,7 @@ public function testGetRawData() /** * @group exif + * @covers \PHPExif\Exif::setRawData */ public function testSetRawData() { @@ -70,6 +73,7 @@ public function testSetRawData() /** * @group exif + * @covers \PHPExif\Exif::getData */ public function testGetData() { @@ -81,6 +85,7 @@ public function testGetData() /** * @group exif + * @covers \PHPExif\Exif::setData */ public function testSetData() { @@ -97,6 +102,29 @@ public function testSetData() /** * * @dataProvider providerUndefinedPropertiesReturnFalse + * @covers \PHPExif\Exif::getAperture + * @covers \PHPExif\Exif::getIso + * @covers \PHPExif\Exif::getExposure + * @covers \PHPExif\Exif::getExposureMilliseconds + * @covers \PHPExif\Exif::getFocusDistance + * @covers \PHPExif\Exif::getWidth + * @covers \PHPExif\Exif::getHeight + * @covers \PHPExif\Exif::getTitle + * @covers \PHPExif\Exif::getCaption + * @covers \PHPExif\Exif::getCopyright + * @covers \PHPExif\Exif::getKeywords + * @covers \PHPExif\Exif::getCamera + * @covers \PHPExif\Exif::getHorizontalResolution + * @covers \PHPExif\Exif::getVerticalResolution + * @covers \PHPExif\Exif::getSoftware + * @covers \PHPExif\Exif::getFocalLength + * @covers \PHPExif\Exif::getCreationDate + * @covers \PHPExif\Exif::getAuthor + * @covers \PHPExif\Exif::getCredit + * @covers \PHPExif\Exif::getSource + * @covers \PHPExif\Exif::getJobtitle + * @covers \PHPExif\Exif::getMimeType + * @covers \PHPExif\Exif::getFileSize * @param string $accessor */ public function testUndefinedPropertiesReturnFalse($accessor) @@ -442,6 +470,10 @@ public function testGetFileSize() $this->assertEquals($expected, $this->exif->getFileSize()); } + /** + * @group exif + * @covers \PHPExif\Exif::getOrientation + */ public function testGetOrientation() { $expected = 1; @@ -466,6 +498,29 @@ public function testGetGPS() * Test that the values returned by both adapters are equal * * @group consistency + * @covers \PHPExif\Exif::getAperture + * @covers \PHPExif\Exif::getIso + * @covers \PHPExif\Exif::getExposure + * @covers \PHPExif\Exif::getExposureMilliseconds + * @covers \PHPExif\Exif::getFocusDistance + * @covers \PHPExif\Exif::getWidth + * @covers \PHPExif\Exif::getHeight + * @covers \PHPExif\Exif::getTitle + * @covers \PHPExif\Exif::getCaption + * @covers \PHPExif\Exif::getCopyright + * @covers \PHPExif\Exif::getKeywords + * @covers \PHPExif\Exif::getCamera + * @covers \PHPExif\Exif::getHorizontalResolution + * @covers \PHPExif\Exif::getVerticalResolution + * @covers \PHPExif\Exif::getSoftware + * @covers \PHPExif\Exif::getFocalLength + * @covers \PHPExif\Exif::getCreationDate + * @covers \PHPExif\Exif::getAuthor + * @covers \PHPExif\Exif::getCredit + * @covers \PHPExif\Exif::getSource + * @covers \PHPExif\Exif::getJobtitle + * @covers \PHPExif\Exif::getMimeType + * @covers \PHPExif\Exif::getFileSize */ public function testAdapterConsistency() { From cf21a3f2e30d678db70da249620ee529d5e345eb Mon Sep 17 00:00:00 2001 From: Tom Van Herreweghe Date: Wed, 1 Apr 2015 13:35:23 +0200 Subject: [PATCH 15/38] Add unit tests for Mutator class Signed-off-by: Tom Van Herreweghe --- tests/PHPExif/Hydrator/MutatorTest.php | 68 ++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 tests/PHPExif/Hydrator/MutatorTest.php diff --git a/tests/PHPExif/Hydrator/MutatorTest.php b/tests/PHPExif/Hydrator/MutatorTest.php new file mode 100644 index 0000000..e37e1d1 --- /dev/null +++ b/tests/PHPExif/Hydrator/MutatorTest.php @@ -0,0 +1,68 @@ + + */ +class MutatorTest extends \PHPUnit_Framework_TestCase +{ + /** + * Setup function before the tests + */ + public function setUp() + { + } + + /** + * @group hydrator + * @covers \PHPExif\Hydrator\Mutator::hydrate + */ + public function testHydrateCallsDetermineMutator() + { + // input data + $input = array( + 'foo' => 'bar', + ); + + // create mock + $mock = $this->getMock('\\PHPExif\\Hydrator\\Mutator', array('determineMutator')); + + $mock->expects($this->exactly(count($input))) + ->method('determineMutator') + ->will($this->returnValue('setFoo')); + + $object = new TestClass(); + + // do the test + $mock->hydrate($object, $input); + } + + /** + * @group hydrator + * @covers \PHPExif\Hydrator\Mutator::hydrate + */ + public function testHydrateCallsMutatorsOnObject() + { + // input data + $input = array( + 'bar' => 'baz', + ); + + // create mock + $mock = $this->getMock('TestClass', array('setBar')); + + $mock->expects($this->once()) + ->method('setBar') + ->with($this->equalTo($input['bar'])); + + // do the test + $hydrator = new \PHPExif\Hydrator\Mutator; + $hydrator->hydrate($mock, $input); + } +} + +class TestClass +{ + public function setBar() + { + } +} + From 2b7fbc6c9521cbe8d1a791a6f63afc4d39b8703f Mon Sep 17 00:00:00 2001 From: Tom Van Herreweghe Date: Wed, 1 Apr 2015 14:37:42 +0200 Subject: [PATCH 16/38] Add extra unit tests for AdapterAbstract Signed-off-by: Tom Van Herreweghe --- tests/PHPExif/Adapter/AdapterAbstractTest.php | 146 ++++++++++++++++++ 1 file changed, 146 insertions(+) diff --git a/tests/PHPExif/Adapter/AdapterAbstractTest.php b/tests/PHPExif/Adapter/AdapterAbstractTest.php index 7b30d48..a020bb3 100644 --- a/tests/PHPExif/Adapter/AdapterAbstractTest.php +++ b/tests/PHPExif/Adapter/AdapterAbstractTest.php @@ -82,4 +82,150 @@ public function testConstructorSetsOptions() $this->assertEquals($value, $reflProp->getValue($adapter)); } } + + /** + * @group adapter + * @covers \PHPExif\Adapter\AdapterAbstract::setMapper + */ + public function testSetMapperReturnsCurrentInstance() + { + $mapper = new \PHPExif\Mapper\Native(); + $result = $this->adapter->setMapper($mapper); + $this->assertSame($this->adapter, $result); + } + + /** + * @group adapter + * @covers \PHPExif\Adapter\AdapterAbstract::setMapper + */ + public function testSetMapperCorrectlySetsInProperty() + { + $mapper = new \PHPExif\Mapper\Native(); + $this->adapter->setMapper($mapper); + + $reflProp = new \ReflectionProperty('\\PHPExif\\Adapter\\AdapterAbstract', 'mapper'); + $reflProp->setAccessible(true); + $this->assertSame($mapper, $reflProp->getValue($this->adapter)); + } + + /** + * @group adapter + * @covers \PHPExif\Adapter\AdapterAbstract::getMapper + */ + public function testGetMapperCorrectlyReturnsFromProperty() + { + $mapper = new \PHPExif\Mapper\Native(); + $reflProp = new \ReflectionProperty('\\PHPExif\\Adapter\\AdapterAbstract', 'mapper'); + $reflProp->setAccessible(true); + $reflProp->setValue($this->adapter, $mapper); + $this->assertSame($mapper, $this->adapter->getMapper()); + } + + /** + * @group adapter + * @covers \PHPExif\Adapter\AdapterAbstract::getMapper + */ + public function testGetMapperLazyLoadsMapperWhenNotPresent() + { + $reflProp = new \ReflectionProperty( + get_class($this->adapter), + 'mapperClass' + ); + + $mapperClass = '\\PHPExif\\Mapper\\Native'; + $reflProp->setAccessible(true); + $reflProp->setValue($this->adapter, $mapperClass); + + $this->assertInstanceOf($mapperClass, $this->adapter->getMapper()); + } + + /** + * @group adapter + * @covers \PHPExif\Adapter\AdapterAbstract::getMapper + */ + public function testGetMapperLazyLoadingSetsInProperty() + { + $reflProp = new \ReflectionProperty( + get_class($this->adapter), + 'mapperClass' + ); + + $mapperClass = '\\PHPExif\\Mapper\\Native'; + $reflProp->setAccessible(true); + $reflProp->setValue($this->adapter, $mapperClass); + + $reflProp2 = new \ReflectionProperty( + get_class($this->adapter), + 'mapper' + ); + $reflProp2->setAccessible(true); + $this->adapter->getMapper(); + $this->assertInstanceOf($mapperClass, $reflProp2->getValue($this->adapter)); + } + + /** + * @group adapter + * @covers \PHPExif\Adapter\AdapterAbstract::setHydrator + */ + public function testSetHydratorReturnsCurrentInstance() + { + $hydrator = new \PHPExif\Hydrator\Mutator(); + $result = $this->adapter->setHydrator($hydrator); + $this->assertSame($this->adapter, $result); + } + + /** + * @group adapter + * @covers \PHPExif\Adapter\AdapterAbstract::setHydrator + */ + public function testSetHydratorCorrectlySetsInProperty() + { + $hydrator = new \PHPExif\Hydrator\Mutator(); + $this->adapter->setHydrator($hydrator); + + $reflProp = new \ReflectionProperty('\\PHPExif\\Adapter\\AdapterAbstract', 'hydrator'); + $reflProp->setAccessible(true); + $this->assertSame($hydrator, $reflProp->getValue($this->adapter)); + } + + /** + * @group adapter + * @covers \PHPExif\Adapter\AdapterAbstract::getHydrator + */ + public function testGetHydratorCorrectlyReturnsFromProperty() + { + $hydrator = new \PHPExif\Hydrator\Mutator(); + $reflProp = new \ReflectionProperty('\\PHPExif\\Adapter\\AdapterAbstract', 'hydrator'); + $reflProp->setAccessible(true); + $reflProp->setValue($this->adapter, $hydrator); + $this->assertSame($hydrator, $this->adapter->getHydrator()); + } + + /** + * @group adapter + * @covers \PHPExif\Adapter\AdapterAbstract::getHydrator + */ + public function testGetHydratorLazyLoadsHydratorWhenNotPresent() + { + $hydratorClass = '\\PHPExif\\Hydrator\\Mutator'; + $this->assertInstanceOf($hydratorClass, $this->adapter->getHydrator()); + } + + /** + * @group adapter + * @covers \PHPExif\Adapter\AdapterAbstract::getHydrator + */ + public function testGetHydratorLazyLoadingSetsInProperty() + { + $hydratorClass = '\\PHPExif\\Hydrator\\Mutator'; + + $reflProp = new \ReflectionProperty( + get_class($this->adapter), + 'hydrator' + ); + $reflProp->setAccessible(true); + $this->adapter->getHydrator(); + $this->assertInstanceOf($hydratorClass, $reflProp->getValue($this->adapter)); + } } + From 281aebd4f371d5ea1394fb6b93f5fa59570b9a2c Mon Sep 17 00:00:00 2001 From: Tom Van Herreweghe Date: Wed, 1 Apr 2015 17:40:39 +0200 Subject: [PATCH 17/38] Add coverage for interfaces & exceptions Signed-off-by: Tom Van Herreweghe --- tests/PHPExif/Adapter/AdapterAbstractTest.php | 1 + tests/PHPExif/Hydrator/MutatorTest.php | 1 + tests/PHPExif/Reader/ReaderTest.php | 2 ++ 3 files changed, 4 insertions(+) diff --git a/tests/PHPExif/Adapter/AdapterAbstractTest.php b/tests/PHPExif/Adapter/AdapterAbstractTest.php index a020bb3..2cae725 100644 --- a/tests/PHPExif/Adapter/AdapterAbstractTest.php +++ b/tests/PHPExif/Adapter/AdapterAbstractTest.php @@ -1,6 +1,7 @@ + * @covers \PHPExif\Adapter\AdapterInterface:: */ class AdapterAbstractTest extends \PHPUnit_Framework_TestCase { diff --git a/tests/PHPExif/Hydrator/MutatorTest.php b/tests/PHPExif/Hydrator/MutatorTest.php index e37e1d1..8bb57e0 100644 --- a/tests/PHPExif/Hydrator/MutatorTest.php +++ b/tests/PHPExif/Hydrator/MutatorTest.php @@ -1,6 +1,7 @@ + * @covers \PHPExif\Hydrator\HydratorInterface:: */ class MutatorTest extends \PHPUnit_Framework_TestCase { diff --git a/tests/PHPExif/Reader/ReaderTest.php b/tests/PHPExif/Reader/ReaderTest.php index 7e8c0c0..a615271 100644 --- a/tests/PHPExif/Reader/ReaderTest.php +++ b/tests/PHPExif/Reader/ReaderTest.php @@ -1,6 +1,8 @@ + * @covers \PHPExif\Reader\ReaderInterface:: + * @covers \PHPExif\Adapter\NoAdapterException:: */ class ReaderTest extends \PHPUnit_Framework_TestCase { From 8214151b8d5acf2160924baf4ca25b3db1e150ed Mon Sep 17 00:00:00 2001 From: Tom Van Herreweghe Date: Wed, 1 Apr 2015 17:51:37 +0200 Subject: [PATCH 18/38] Beter interface coverage? Signed-off-by: Tom Van Herreweghe --- tests/PHPExif/Adapter/AdapterAbstractTest.php | 2 +- tests/PHPExif/Hydrator/MutatorTest.php | 2 +- tests/PHPExif/Reader/ReaderTest.php | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/PHPExif/Adapter/AdapterAbstractTest.php b/tests/PHPExif/Adapter/AdapterAbstractTest.php index 2cae725..46982da 100644 --- a/tests/PHPExif/Adapter/AdapterAbstractTest.php +++ b/tests/PHPExif/Adapter/AdapterAbstractTest.php @@ -1,7 +1,7 @@ - * @covers \PHPExif\Adapter\AdapterInterface:: + * @covers \PHPExif\Adapter\AdapterInterface */ class AdapterAbstractTest extends \PHPUnit_Framework_TestCase { diff --git a/tests/PHPExif/Hydrator/MutatorTest.php b/tests/PHPExif/Hydrator/MutatorTest.php index 8bb57e0..280188b 100644 --- a/tests/PHPExif/Hydrator/MutatorTest.php +++ b/tests/PHPExif/Hydrator/MutatorTest.php @@ -1,7 +1,7 @@ - * @covers \PHPExif\Hydrator\HydratorInterface:: + * @covers \PHPExif\Hydrator\HydratorInterface */ class MutatorTest extends \PHPUnit_Framework_TestCase { diff --git a/tests/PHPExif/Reader/ReaderTest.php b/tests/PHPExif/Reader/ReaderTest.php index a615271..f3fa22b 100644 --- a/tests/PHPExif/Reader/ReaderTest.php +++ b/tests/PHPExif/Reader/ReaderTest.php @@ -1,8 +1,8 @@ - * @covers \PHPExif\Reader\ReaderInterface:: - * @covers \PHPExif\Adapter\NoAdapterException:: + * @covers \PHPExif\Reader\ReaderInterface + * @covers \PHPExif\Adapter\NoAdapterException */ class ReaderTest extends \PHPUnit_Framework_TestCase { From f4eaad8640ab4da9e9437d67cc934e45d638dde8 Mon Sep 17 00:00:00 2001 From: Tom Van Herreweghe Date: Wed, 1 Apr 2015 18:03:14 +0200 Subject: [PATCH 19/38] Add coverage ignore tags Signed-off-by: Tom Van Herreweghe --- lib/PHPExif/Adapter/AdapterInterface.php | 1 + lib/PHPExif/Adapter/NoAdapterException.php | 1 + lib/PHPExif/Hydrator/HydratorInterface.php | 1 + lib/PHPExif/Mapper/MapperInterface.php | 1 + lib/PHPExif/Reader/ReaderInterface.php | 19 +++++++++++++++++++ 5 files changed, 23 insertions(+) diff --git a/lib/PHPExif/Adapter/AdapterInterface.php b/lib/PHPExif/Adapter/AdapterInterface.php index fc44802..780e77d 100644 --- a/lib/PHPExif/Adapter/AdapterInterface.php +++ b/lib/PHPExif/Adapter/AdapterInterface.php @@ -7,6 +7,7 @@ * @license http://github.com/miljar/PHPExif/blob/master/LICENSE MIT License * @category PHPExif * @package Reader + * @codeCoverageIgnore */ namespace PHPExif\Adapter; diff --git a/lib/PHPExif/Adapter/NoAdapterException.php b/lib/PHPExif/Adapter/NoAdapterException.php index 6d56104..8a2b011 100644 --- a/lib/PHPExif/Adapter/NoAdapterException.php +++ b/lib/PHPExif/Adapter/NoAdapterException.php @@ -7,6 +7,7 @@ * @license http://github.com/miljar/PHPExif/blob/master/LICENSE MIT License * @category PHPExif * @package Reader + * @codeCoverageIgnore */ namespace PHPExif\Adapter; diff --git a/lib/PHPExif/Hydrator/HydratorInterface.php b/lib/PHPExif/Hydrator/HydratorInterface.php index fd8b797..d884327 100644 --- a/lib/PHPExif/Hydrator/HydratorInterface.php +++ b/lib/PHPExif/Hydrator/HydratorInterface.php @@ -7,6 +7,7 @@ * @license http://github.com/miljar/PHPExif/blob/master/LICENSE MIT License * @category PHPExif * @package Hydrator + * @codeCoverageIgnore */ namespace PHPExif\Hydrator; diff --git a/lib/PHPExif/Mapper/MapperInterface.php b/lib/PHPExif/Mapper/MapperInterface.php index 0479740..89a20e0 100644 --- a/lib/PHPExif/Mapper/MapperInterface.php +++ b/lib/PHPExif/Mapper/MapperInterface.php @@ -7,6 +7,7 @@ * @license http://github.com/miljar/PHPExif/blob/master/LICENSE MIT License * @category PHPExif * @package Mapper + * @codeCoverageIgnore */ namespace PHPExif\Mapper; diff --git a/lib/PHPExif/Reader/ReaderInterface.php b/lib/PHPExif/Reader/ReaderInterface.php index 76423e2..9617396 100644 --- a/lib/PHPExif/Reader/ReaderInterface.php +++ b/lib/PHPExif/Reader/ReaderInterface.php @@ -1,7 +1,26 @@ + * @license http://github.com/miljar/PHPExif/blob/master/LICENSE MIT License + * @category PHPExif + * @package Reader + * @codeCoverageIgnore + */ namespace PHPExif\Reader; +/** + * PHP Exif Reader + * + * Defines the interface for reader functionality + * + * @category PHPExif + * @package Reader + */ interface ReaderInterface { /** From 836ac7c4a55aa476cc7f9e730d2886467ab447b7 Mon Sep 17 00:00:00 2001 From: Tom Van Herreweghe Date: Thu, 2 Apr 2015 10:09:36 +0200 Subject: [PATCH 20/38] Add unit test for Exif mutators Signed-off-by: Tom Van Herreweghe --- lib/PHPExif/Exif.php | 8 +++--- tests/PHPExif/ExifTest.php | 56 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+), 4 deletions(-) diff --git a/lib/PHPExif/Exif.php b/lib/PHPExif/Exif.php index bbf1bea..f9c2b2f 100755 --- a/lib/PHPExif/Exif.php +++ b/lib/PHPExif/Exif.php @@ -704,7 +704,7 @@ public function setCreationDate(\DateTime $value) /** * Returns the colorspace, if it exists * - * @return string + * @return string|boolean */ public function getColorSpace() { @@ -731,7 +731,7 @@ public function setColorSpace($value) /** * Returns the mimetype, if it exists * - * @return string + * @return string|boolean */ public function getMimeType() { @@ -758,7 +758,7 @@ public function setMimeType($value) /** * Returns the filesize, if it exists * - * @return int + * @return int|boolean */ public function getFileSize() { @@ -785,7 +785,7 @@ public function setFileSize($value) /** * Returns the orientation, if it exists * - * @return int + * @return int|boolean */ public function getOrientation() { diff --git a/tests/PHPExif/ExifTest.php b/tests/PHPExif/ExifTest.php index 7e8d420..8009eee 100755 --- a/tests/PHPExif/ExifTest.php +++ b/tests/PHPExif/ExifTest.php @@ -494,6 +494,62 @@ public function testGetGPS() $this->assertEquals($expected, $this->exif->getGPS()); } + /** + * @group exif + * @covers \PHPExif\Exif::setAperture + * @covers \PHPExif\Exif::setIso + * @covers \PHPExif\Exif::setExposure + * @covers \PHPExif\Exif::setExposureMilliseconds + * @covers \PHPExif\Exif::setFocusDistance + * @covers \PHPExif\Exif::setWidth + * @covers \PHPExif\Exif::setHeight + * @covers \PHPExif\Exif::setTitle + * @covers \PHPExif\Exif::setCaption + * @covers \PHPExif\Exif::setCopyright + * @covers \PHPExif\Exif::setKeywords + * @covers \PHPExif\Exif::setCamera + * @covers \PHPExif\Exif::setHorizontalResolution + * @covers \PHPExif\Exif::setVerticalResolution + * @covers \PHPExif\Exif::setSoftware + * @covers \PHPExif\Exif::setFocalLength + * @covers \PHPExif\Exif::setCreationDate + * @covers \PHPExif\Exif::setAuthor + * @covers \PHPExif\Exif::setCredit + * @covers \PHPExif\Exif::setSource + * @covers \PHPExif\Exif::setJobtitle + * @covers \PHPExif\Exif::setMimeType + * @covers \PHPExif\Exif::setFileSize + */ + public function testMutatorMethodsSetInProperty() + { + $reflClass = new \ReflectionClass(get_class($this->exif)); + $constants = $reflClass->getConstants(); + + $reflProp = new \ReflectionProperty(get_class($this->exif), 'data'); + $reflProp->setAccessible(true); + + $expected = 'foo'; + foreach ($constants as $name => $value) { + $setter = 'set' . ucfirst($value); + + switch ($value) { + case 'creationdate': + $now = new \DateTime(); + $this->exif->$setter($now); + $propertyValue = $reflProp->getValue($this->exif); + $this->assertSame($now, $propertyValue[$value]); + break; + case 'focalDistance': + $setter = 'setFocusDistance'; + default: + $this->exif->$setter($expected); + $propertyValue = $reflProp->getValue($this->exif); + $this->assertEquals($expected, $propertyValue[$value]); + break; + } + } + } + /** * Test that the values returned by both adapters are equal * From 06a75fd1c85f07c56afdbada10383189451fa227 Mon Sep 17 00:00:00 2001 From: Tom Van Herreweghe Date: Thu, 2 Apr 2015 10:18:50 +0200 Subject: [PATCH 21/38] Improved coverage annotations on Exif class Signed-off-by: Tom Van Herreweghe --- tests/PHPExif/ExifTest.php | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/tests/PHPExif/ExifTest.php b/tests/PHPExif/ExifTest.php index 8009eee..06e19b8 100755 --- a/tests/PHPExif/ExifTest.php +++ b/tests/PHPExif/ExifTest.php @@ -125,6 +125,9 @@ public function testSetData() * @covers \PHPExif\Exif::getJobtitle * @covers \PHPExif\Exif::getMimeType * @covers \PHPExif\Exif::getFileSize + * @covers \PHPExif\Exif::getHeadline + * @covers \PHPExif\Exif::getColorSpace + * @covers \PHPExif\Exif::getOrientation * @param string $accessor */ public function testUndefinedPropertiesReturnFalse($accessor) @@ -165,6 +168,9 @@ public function providerUndefinedPropertiesReturnFalse() array('getJobtitle'), array('getMimeType'), array('getFileSize'), + array('getHeadline'), + array('getColorSpace'), + array('getOrientation'), ); } @@ -499,7 +505,6 @@ public function testGetGPS() * @covers \PHPExif\Exif::setAperture * @covers \PHPExif\Exif::setIso * @covers \PHPExif\Exif::setExposure - * @covers \PHPExif\Exif::setExposureMilliseconds * @covers \PHPExif\Exif::setFocusDistance * @covers \PHPExif\Exif::setWidth * @covers \PHPExif\Exif::setHeight @@ -519,6 +524,9 @@ public function testGetGPS() * @covers \PHPExif\Exif::setJobtitle * @covers \PHPExif\Exif::setMimeType * @covers \PHPExif\Exif::setFileSize + * @covers \PHPExif\Exif::setHeadline + * @covers \PHPExif\Exif::setColorSpace + * @covers \PHPExif\Exif::setOrientation */ public function testMutatorMethodsSetInProperty() { From 52bbeef5c680988e9d7ffa717961ad370ce2d092 Mon Sep 17 00:00:00 2001 From: Tom Van Herreweghe Date: Thu, 2 Apr 2015 10:24:54 +0200 Subject: [PATCH 22/38] Removed unnecessary initialization of variable in Reader class Signed-off-by: Tom Van Herreweghe --- lib/PHPExif/Reader/Reader.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/PHPExif/Reader/Reader.php b/lib/PHPExif/Reader/Reader.php index 241193e..34b7bb5 100755 --- a/lib/PHPExif/Reader/Reader.php +++ b/lib/PHPExif/Reader/Reader.php @@ -72,7 +72,6 @@ public function getAdapter() public static function factory($type) { $classname = get_called_class(); - $adapter = null; switch ($type) { case self::TYPE_NATIVE: $adapter = new NativeAdapter(); @@ -84,7 +83,6 @@ public static function factory($type) throw new \InvalidArgumentException( sprintf('Unknown type "%1$s"', $type) ); - break; } return new $classname($adapter); } From 8fca517e0174d9bd6355d6b3a762bd4a9d26f6bb Mon Sep 17 00:00:00 2001 From: Tom Van Herreweghe Date: Thu, 2 Apr 2015 10:25:36 +0200 Subject: [PATCH 23/38] Removed indenting level in Native mapper class Signed-off-by: Tom Van Herreweghe --- lib/PHPExif/Mapper/Native.php | 28 ++++++++++++---------------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/lib/PHPExif/Mapper/Native.php b/lib/PHPExif/Mapper/Native.php index 689c983..b10f461 100644 --- a/lib/PHPExif/Mapper/Native.php +++ b/lib/PHPExif/Mapper/Native.php @@ -82,22 +82,18 @@ class Native implements MapperInterface * @var array */ protected $map = array( - //self::SECTION_COMPUTED => array( - self::APERTUREFNUMBER => Exif::APERTURE, - self::FOCUSDISTANCE => Exif::FOCAL_DISTANCE, - self::HEIGHT => Exif::HEIGHT, - self::WIDTH => Exif::WIDTH, - //), - //self::SECTION_IPTC => array( - self::CAPTION => Exif::CAPTION, - self::COPYRIGHT => Exif::COPYRIGHT, - self::CREDIT => Exif::CREDIT, - self::HEADLINE => Exif::HEADLINE, - self::JOBTITLE => Exif::JOB_TITLE, - self::KEYWORDS => Exif::KEYWORDS, - self::SOURCE => Exif::SOURCE, - self::TITLE => Exif::TITLE, - //), + self::APERTUREFNUMBER => Exif::APERTURE, + self::FOCUSDISTANCE => Exif::FOCAL_DISTANCE, + self::HEIGHT => Exif::HEIGHT, + self::WIDTH => Exif::WIDTH, + self::CAPTION => Exif::CAPTION, + self::COPYRIGHT => Exif::COPYRIGHT, + self::CREDIT => Exif::CREDIT, + self::HEADLINE => Exif::HEADLINE, + self::JOBTITLE => Exif::JOB_TITLE, + self::KEYWORDS => Exif::KEYWORDS, + self::SOURCE => Exif::SOURCE, + self::TITLE => Exif::TITLE, self::ARTIST => Exif::AUTHOR, self::MODEL => Exif::CAMERA, self::COLORSPACE => Exif::COLORSPACE, From 589995212d23b06bcdfb06f9cba39060b4def9af Mon Sep 17 00:00:00 2001 From: Tom Van Herreweghe Date: Thu, 2 Apr 2015 10:27:40 +0200 Subject: [PATCH 24/38] Improved docblocks & removed unused variable Signed-off-by: Tom Van Herreweghe --- lib/PHPExif/Adapter/Native.php | 2 +- lib/PHPExif/Mapper/Exiftool.php | 2 +- lib/PHPExif/Mapper/MapperInterface.php | 2 +- lib/PHPExif/Mapper/Native.php | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/PHPExif/Adapter/Native.php b/lib/PHPExif/Adapter/Native.php index 862aa5a..c5405e9 100644 --- a/lib/PHPExif/Adapter/Native.php +++ b/lib/PHPExif/Adapter/Native.php @@ -216,7 +216,7 @@ public function getExifFromFile($file) */ public function getIptcData($file) { - $size = getimagesize($file, $info); + getimagesize($file, $info); $arrData = array(); if (isset($info['APP13'])) { $iptc = iptcparse($info['APP13']); diff --git a/lib/PHPExif/Mapper/Exiftool.php b/lib/PHPExif/Mapper/Exiftool.php index 3baa68a..9a581a6 100644 --- a/lib/PHPExif/Mapper/Exiftool.php +++ b/lib/PHPExif/Mapper/Exiftool.php @@ -91,7 +91,7 @@ class Exiftool implements MapperInterface * fields for the \PHPExif\Exif class * * @param array $data - * @return void + * @return array */ public function mapRawData(array $data) { diff --git a/lib/PHPExif/Mapper/MapperInterface.php b/lib/PHPExif/Mapper/MapperInterface.php index 89a20e0..5f5097e 100644 --- a/lib/PHPExif/Mapper/MapperInterface.php +++ b/lib/PHPExif/Mapper/MapperInterface.php @@ -27,7 +27,7 @@ interface MapperInterface * fields for the \PHPExif\Exif class * * @param array $data - * @return void + * @return array */ public function mapRawData(array $data); } diff --git a/lib/PHPExif/Mapper/Native.php b/lib/PHPExif/Mapper/Native.php index b10f461..4b1c31b 100644 --- a/lib/PHPExif/Mapper/Native.php +++ b/lib/PHPExif/Mapper/Native.php @@ -114,7 +114,7 @@ class Native implements MapperInterface * fields for the \PHPExif\Exif class * * @param array $data - * @return void + * @return array */ public function mapRawData(array $data) { From 32b43589f1a5be9915e290264e0670bb377c1048 Mon Sep 17 00:00:00 2001 From: Tom Van Herreweghe Date: Thu, 2 Apr 2015 11:06:04 +0200 Subject: [PATCH 25/38] Changed docblocks for AbstractAdapter constructor Signed-off-by: Tom Van Herreweghe --- lib/PHPExif/Adapter/AdapterAbstract.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/PHPExif/Adapter/AdapterAbstract.php b/lib/PHPExif/Adapter/AdapterAbstract.php index d4b122e..51050eb 100644 --- a/lib/PHPExif/Adapter/AdapterAbstract.php +++ b/lib/PHPExif/Adapter/AdapterAbstract.php @@ -42,7 +42,7 @@ abstract class AdapterAbstract implements AdapterInterface /** * Class constructor * - * @param array $data Optional array of data to initialize the object with + * @param array $options Optional array of data to initialize the object with */ public function __construct(array $options = array()) { From 874d64558d8a632df3faf5744b3836bd9c8fd719 Mon Sep 17 00:00:00 2001 From: Tom Van Herreweghe Date: Thu, 2 Apr 2015 11:10:05 +0200 Subject: [PATCH 26/38] Removed obsolete ; in docblocks Signed-off-by: Tom Van Herreweghe --- lib/PHPExif/Adapter/AdapterAbstract.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/PHPExif/Adapter/AdapterAbstract.php b/lib/PHPExif/Adapter/AdapterAbstract.php index 51050eb..9e0315a 100644 --- a/lib/PHPExif/Adapter/AdapterAbstract.php +++ b/lib/PHPExif/Adapter/AdapterAbstract.php @@ -55,7 +55,7 @@ public function __construct(array $options = array()) * Mutator for the data mapper * * @param \PHPExif\Mapper\MapperInterface $mapper - * @return \PHPExif\Adapter\AdapterInterface; + * @return \PHPExif\Adapter\AdapterInterface */ public function setMapper(MapperInterface $mapper) { @@ -85,7 +85,7 @@ public function getMapper() * Mutator for the hydrator * * @param \PHPExif\Hydrator\HydratorInterface $hydrator - * @return \PHPExif\Adapter\AdapterInterface; + * @return \PHPExif\Adapter\AdapterInterface */ public function setHydrator(HydratorInterface $hydrator) { From 86c4dac8ada202e2926bc80e3658e10ad9186518 Mon Sep 17 00:00:00 2001 From: Tom Van Herreweghe Date: Thu, 2 Apr 2015 12:30:34 +0200 Subject: [PATCH 27/38] Unit tests for Exiftool mapper Signed-off-by: Tom Van Herreweghe --- lib/PHPExif/Mapper/Exiftool.php | 2 +- tests/PHPExif/Mapper/ExiftoolMapperTest.php | 147 ++++++++++++++++++++ 2 files changed, 148 insertions(+), 1 deletion(-) create mode 100644 tests/PHPExif/Mapper/ExiftoolMapperTest.php diff --git a/lib/PHPExif/Mapper/Exiftool.php b/lib/PHPExif/Mapper/Exiftool.php index 9a581a6..ddb6661 100644 --- a/lib/PHPExif/Mapper/Exiftool.php +++ b/lib/PHPExif/Mapper/Exiftool.php @@ -62,7 +62,6 @@ class Exiftool implements MapperInterface self::ARTIST => Exif::AUTHOR, self::MODEL => Exif::CAMERA, self::CAPTION => Exif::CAPTION, - self::CAPTIONABSTRACT => Exif::CAPTION, self::COLORSPACE => Exif::COLORSPACE, self::COPYRIGHT => Exif::COPYRIGHT, self::CREATEDATE => Exif::CREATION_DATE, @@ -84,6 +83,7 @@ class Exiftool implements MapperInterface self::TITLE => Exif::TITLE, self::YRESOLUTION => Exif::VERTICAL_RESOLUTION, self::IMAGEWIDTH => Exif::WIDTH, + self::CAPTIONABSTRACT => Exif::CAPTION, ); /** diff --git a/tests/PHPExif/Mapper/ExiftoolMapperTest.php b/tests/PHPExif/Mapper/ExiftoolMapperTest.php new file mode 100644 index 0000000..fbe8846 --- /dev/null +++ b/tests/PHPExif/Mapper/ExiftoolMapperTest.php @@ -0,0 +1,147 @@ + + */ +class ExiftoolMapperTest extends \PHPUnit_Framework_TestCase +{ + protected $mapper; + + public function setUp() + { + $this->mapper = new \PHPExif\Mapper\Exiftool; + } + + /** + * @group mapper + * @covers \PHPExif\Mapper\Exiftool::__construct + */ + public function testMapRawDataImplementsCorrectInterface() + { + $this->assertInstanceOf('\\PHPExif\\Mapper\\MapperInterface', $this->mapper); + } + + /** + * @group mapper + * @covers \PHPExif\Mapper\Exiftool::mapRawData + */ + public function testMapRawDataIgnoresFieldIfItDoesntExist() + { + $rawData = array('foo' => 'bar'); + $mapped = $this->mapper->mapRawData($rawData); + + $this->assertCount(0, $mapped); + } + + /** + * @group mapper + * @covers \PHPExif\Mapper\Exiftool::mapRawData + */ + public function testMapRawDataMapsFieldsCorrectly() + { + $reflProp = new \ReflectionProperty(get_class($this->mapper), 'map'); + $reflProp->setAccessible(true); + $map = $reflProp->getValue($this->mapper); + + // ignore custom formatted data stuff: + unset($map[\PHPExif\Mapper\Exiftool::APERTURE]); + unset($map[\PHPExif\Mapper\Exiftool::APPROXIMATEFOCUSDISTANCE]); + unset($map[\PHPExif\Mapper\Exiftool::CREATEDATE]); + unset($map[\PHPExif\Mapper\Exiftool::EXPOSURETIME]); + unset($map[\PHPExif\Mapper\Exiftool::FOCALLENGTH]); + + // create raw data + $keys = array_keys($map); + $values = array(); + $values = array_pad($values, count($keys), 'foo'); + $rawData = array_combine($keys, $values); + + + $mapped = $this->mapper->mapRawData($rawData); + + $i = 0; + foreach ($mapped as $key => $value) { + $this->assertEquals($map[$keys[$i]], $key); + $i++; + } + } + + /** + * @group mapper + * @covers \PHPExif\Mapper\Exiftool::mapRawData + */ + public function testMapRawDataCorrectlyFormatsAperture() + { + $rawData = array( + \PHPExif\Mapper\Exiftool::APERTURE => 0.123, + ); + + $mapped = $this->mapper->mapRawData($rawData); + + $this->assertEquals('f/0.1', reset($mapped)); + } + + /** + * @group mapper + * @covers \PHPExif\Mapper\Exiftool::mapRawData + */ + public function testMapRawDataCorrectlyFormatsFocusDistance() + { + $rawData = array( + \PHPExif\Mapper\Exiftool::APPROXIMATEFOCUSDISTANCE => 50, + ); + + $mapped = $this->mapper->mapRawData($rawData); + + $this->assertEquals('50m', reset($mapped)); + } + + /** + * @group mapper + * @covers \PHPExif\Mapper\Exiftool::mapRawData + */ + public function testMapRawDataCorrectlyFormatsCreationDate() + { + $rawData = array( + \PHPExif\Mapper\Exiftool::CREATEDATE => '2015:04:01 12:11:09', + ); + + $mapped = $this->mapper->mapRawData($rawData); + + $result = reset($mapped); + $this->assertInstanceOf('\\DateTime', $result); + $this->assertEquals( + reset($rawData), + $result->format('Y:m:d H:i:s') + ); + } + + /** + * @group mapper + * @covers \PHPExif\Mapper\Exiftool::mapRawData + */ + public function testMapRawDataCorrectlyFormatsExposureTime() + { + $rawData = array( + \PHPExif\Mapper\Exiftool::EXPOSURETIME => 1/400, + ); + + $mapped = $this->mapper->mapRawData($rawData); + + $this->assertEquals('1/400', reset($mapped)); + } + + /** + * @group mapper + * @covers \PHPExif\Mapper\Exiftool::mapRawData + */ + public function testMapRawDataCorrectlyFormatsFocalLength() + { + $rawData = array( + \PHPExif\Mapper\Exiftool::FOCALLENGTH => '15 m', + ); + + $mapped = $this->mapper->mapRawData($rawData); + + $this->assertEquals(15, reset($mapped)); + } +} From 7b16cd4069c24b737227d94eef459089493e92ad Mon Sep 17 00:00:00 2001 From: Tom Van Herreweghe Date: Thu, 2 Apr 2015 12:36:21 +0200 Subject: [PATCH 28/38] Removed incorrect coverage tag Signed-off-by: Tom Van Herreweghe --- tests/PHPExif/Mapper/ExiftoolMapperTest.php | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/PHPExif/Mapper/ExiftoolMapperTest.php b/tests/PHPExif/Mapper/ExiftoolMapperTest.php index fbe8846..d012e95 100644 --- a/tests/PHPExif/Mapper/ExiftoolMapperTest.php +++ b/tests/PHPExif/Mapper/ExiftoolMapperTest.php @@ -13,7 +13,6 @@ public function setUp() /** * @group mapper - * @covers \PHPExif\Mapper\Exiftool::__construct */ public function testMapRawDataImplementsCorrectInterface() { From a2a0272c1a4ac357bfab1a0f6fdc42007a82bc4e Mon Sep 17 00:00:00 2001 From: Tom Van Herreweghe Date: Fri, 3 Apr 2015 11:49:31 +0200 Subject: [PATCH 29/38] Unit test for Native mapper Signed-off-by: Tom Van Herreweghe --- tests/PHPExif/Mapper/ExiftoolMapperTest.php | 2 +- tests/PHPExif/Mapper/NativeMapperTest.php | 169 ++++++++++++++++++++ 2 files changed, 170 insertions(+), 1 deletion(-) create mode 100644 tests/PHPExif/Mapper/NativeMapperTest.php diff --git a/tests/PHPExif/Mapper/ExiftoolMapperTest.php b/tests/PHPExif/Mapper/ExiftoolMapperTest.php index d012e95..061872e 100644 --- a/tests/PHPExif/Mapper/ExiftoolMapperTest.php +++ b/tests/PHPExif/Mapper/ExiftoolMapperTest.php @@ -14,7 +14,7 @@ public function setUp() /** * @group mapper */ - public function testMapRawDataImplementsCorrectInterface() + public function testClassImplementsCorrectInterface() { $this->assertInstanceOf('\\PHPExif\\Mapper\\MapperInterface', $this->mapper); } diff --git a/tests/PHPExif/Mapper/NativeMapperTest.php b/tests/PHPExif/Mapper/NativeMapperTest.php new file mode 100644 index 0000000..1f4e8de --- /dev/null +++ b/tests/PHPExif/Mapper/NativeMapperTest.php @@ -0,0 +1,169 @@ + + */ +class NativeMapperTest extends \PHPUnit_Framework_TestCase +{ + protected $mapper; + + public function setUp() + { + $this->mapper = new \PHPExif\Mapper\Native; + } + + /** + * @group mapper + */ + public function testClassImplementsCorrectInterface() + { + $this->assertInstanceOf('\\PHPExif\\Mapper\\MapperInterface', $this->mapper); + } + + /** + * @group mapper + * @covers \PHPExif\Mapper\Native::mapRawData + */ + public function testMapRawDataIgnoresFieldIfItDoesntExist() + { + $rawData = array('foo' => 'bar'); + $mapped = $this->mapper->mapRawData($rawData); + + $this->assertCount(0, $mapped); + } + + /** + * @group mapper + * @covers \PHPExif\Mapper\Native::mapRawData + */ + public function testMapRawDataMapsFieldsCorrectly() + { + $reflProp = new \ReflectionProperty(get_class($this->mapper), 'map'); + $reflProp->setAccessible(true); + $map = $reflProp->getValue($this->mapper); + + // ignore custom formatted data stuff: + unset($map[\PHPExif\Mapper\Native::DATETIMEORIGINAL]); + unset($map[\PHPExif\Mapper\Native::EXPOSURETIME]); + unset($map[\PHPExif\Mapper\Native::FOCALLENGTH]); + unset($map[\PHPExif\Mapper\Native::XRESOLUTION]); + unset($map[\PHPExif\Mapper\Native::YRESOLUTION]); + + // create raw data + $keys = array_keys($map); + $values = array(); + $values = array_pad($values, count($keys), 'foo'); + $rawData = array_combine($keys, $values); + + + $mapped = $this->mapper->mapRawData($rawData); + + $i = 0; + foreach ($mapped as $key => $value) { + $this->assertEquals($map[$keys[$i]], $key); + $i++; + } + } + + /** + * @group mapper + * @covers \PHPExif\Mapper\Native::mapRawData + */ + public function testMapRawDataCorrectlyFormatsDateTimeOriginal() + { + $rawData = array( + \PHPExif\Mapper\Native::DATETIMEORIGINAL => '2015:04:01 12:11:09', + ); + + $mapped = $this->mapper->mapRawData($rawData); + + $result = reset($mapped); + $this->assertInstanceOf('\\DateTime', $result); + $this->assertEquals( + reset($rawData), + $result->format('Y:m:d H:i:s') + ); + } + + /** + * @group mapper + * @covers \PHPExif\Mapper\Native::mapRawData + */ + public function testMapRawDataCorrectlyFormatsExposureTime() + { + $rawData = array( + \PHPExif\Mapper\Native::EXPOSURETIME => '2/800', + ); + + $mapped = $this->mapper->mapRawData($rawData); + + $this->assertEquals('1/400', reset($mapped)); + } + + /** + * @group mapper + * @covers \PHPExif\Mapper\Native::mapRawData + */ + public function testMapRawDataCorrectlyFormatsFocalLength() + { + $rawData = array( + \PHPExif\Mapper\Native::FOCALLENGTH => '30/5', + ); + + $mapped = $this->mapper->mapRawData($rawData); + + $this->assertEquals(6, reset($mapped)); + } + + /** + * @group mapper + * @covers \PHPExif\Mapper\Native::mapRawData + */ + public function testMapRawDataCorrectlyFormatsXResolution() + { + $rawData = array( + \PHPExif\Mapper\Native::XRESOLUTION => '1500/300', + ); + + $mapped = $this->mapper->mapRawData($rawData); + + $this->assertEquals(1500, reset($mapped)); + } + + /** + * @group mapper + * @covers \PHPExif\Mapper\Native::mapRawData + */ + public function testMapRawDataCorrectlyFormatsYResolution() + { + $rawData = array( + \PHPExif\Mapper\Native::YRESOLUTION => '1500/300', + ); + + $mapped = $this->mapper->mapRawData($rawData); + + $this->assertEquals(1500, reset($mapped)); + } + + /** + * @group mapper + * @covers \PHPExif\Mapper\Native::mapRawData + */ + public function testMapRawDataFlattensRawDataWithSections() + { + $rawData = array( + \PHPExif\Mapper\Native::SECTION_COMPUTED => array( + \PHPExif\Mapper\Native::TITLE => 'Hello', + ), + \PHPExif\Mapper\Native::HEADLINE => 'Headline', + ); + $mapped = $this->mapper->mapRawData($rawData); + $this->assertCount(2, $mapped); + $keys = array_keys($mapped); + + $expected = array( + \PHPExif\Mapper\Native::TITLE, + \PHPExif\Mapper\Native::HEADLINE + ); + $this->assertEquals($expected, $keys); + } +} From cc6fbb798fd1009cd2917b58cff25c514202a71d Mon Sep 17 00:00:00 2001 From: Tom Van Herreweghe Date: Fri, 3 Apr 2015 12:01:53 +0200 Subject: [PATCH 30/38] Exclude Interfaces from coverage report Signed-off-by: Tom Van Herreweghe --- phpunit.xml.dist | 1 + 1 file changed, 1 insertion(+) diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 7a43d54..7470936 100755 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -14,6 +14,7 @@ ./lib ./autoload.php + *Interface.php From 6dbc5942d9c3b1f0b23efe1dbf0a2f3aaec58655 Mon Sep 17 00:00:00 2001 From: Tom Van Herreweghe Date: Fri, 3 Apr 2015 12:02:05 +0200 Subject: [PATCH 31/38] Added @covers annotation for the NoAdapterException Signed-off-by: Tom Van Herreweghe --- tests/PHPExif/Reader/ReaderTest.php | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/PHPExif/Reader/ReaderTest.php b/tests/PHPExif/Reader/ReaderTest.php index f3fa22b..82aa133 100644 --- a/tests/PHPExif/Reader/ReaderTest.php +++ b/tests/PHPExif/Reader/ReaderTest.php @@ -53,6 +53,7 @@ public function testGetAdapterFromProperty() /** * @group reader * @covers \PHPExif\Reader\Reader::getAdapter + * @covers \PHPExif\Adapter\NoAdapterException * @expectedException \PHPExif\Adapter\NoAdapterException */ public function testGetAdapterThrowsExceptionWhenNoAdapterIsSet() From a862beadffe1ac00cc939e50310580fb48ac64d6 Mon Sep 17 00:00:00 2001 From: Tom Van Herreweghe Date: Fri, 3 Apr 2015 12:13:23 +0200 Subject: [PATCH 32/38] Tried mocking proc_open function for coverage Signed-off-by: Tom Van Herreweghe --- .../PHPExif/Adapter/ExiftoolProcOpenTest.php | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 tests/PHPExif/Adapter/ExiftoolProcOpenTest.php diff --git a/tests/PHPExif/Adapter/ExiftoolProcOpenTest.php b/tests/PHPExif/Adapter/ExiftoolProcOpenTest.php new file mode 100644 index 0000000..509bd66 --- /dev/null +++ b/tests/PHPExif/Adapter/ExiftoolProcOpenTest.php @@ -0,0 +1,46 @@ + + */ + class ExiftoolProcOpenTest extends \PHPUnit_Framework_TestCase + { + /** + * @var \PHPExif\Adapter\Exiftool + */ + protected $adapter; + + public function setUp() + { + $this->adapter = new \PHPExif\Adapter\Exiftool(); + } + /** + * @group exiftool + * @covers \PHPExif\Adapter\Exiftool::getCliOutput + */ + public function testGetCliOutput() + { + $reflMethod = new \ReflectionMethod('\PHPExif\Adapter\Exiftool', 'getCliOutput'); + $reflMethod->setAccessible(true); + + $result = $reflMethod->invoke( + $this->adapter, + sprintf( + '%1$s', + 'pwd' + ) + ); + + $this->assertInternalType('string', $result); + } + } +} From 795fab58b9ff0626e5a2d18e245cebd397a942cc Mon Sep 17 00:00:00 2001 From: Tom Van Herreweghe Date: Fri, 3 Apr 2015 12:56:24 +0200 Subject: [PATCH 33/38] Corrected stubbing of root function Signed-off-by: Tom Van Herreweghe --- .../PHPExif/Adapter/ExiftoolProcOpenTest.php | 34 +++++++++++++++---- 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/tests/PHPExif/Adapter/ExiftoolProcOpenTest.php b/tests/PHPExif/Adapter/ExiftoolProcOpenTest.php index 509bd66..9d9bd39 100644 --- a/tests/PHPExif/Adapter/ExiftoolProcOpenTest.php +++ b/tests/PHPExif/Adapter/ExiftoolProcOpenTest.php @@ -1,14 +1,28 @@ */ @@ -21,11 +35,21 @@ class ExiftoolProcOpenTest extends \PHPUnit_Framework_TestCase public function setUp() { + global $mockProcOpen; + $mockProcOpen = true; $this->adapter = new \PHPExif\Adapter\Exiftool(); } + + public function tearDown() + { + global $mockProcOpen; + $mockProcOpen = false; + } + /** * @group exiftool * @covers \PHPExif\Adapter\Exiftool::getCliOutput + * @expectedException RuntimeException */ public function testGetCliOutput() { @@ -39,8 +63,6 @@ public function testGetCliOutput() 'pwd' ) ); - - $this->assertInternalType('string', $result); } } } From 476367b4b260d85a0a8d4459cc64bf4290bf8bdd Mon Sep 17 00:00:00 2001 From: Tom Van Herreweghe Date: Fri, 3 Apr 2015 16:46:39 +0200 Subject: [PATCH 34/38] Add GPS code Signed-off-by: Tom Van Herreweghe --- lib/PHPExif/Adapter/Exiftool.php | 8 ++- lib/PHPExif/Exif.php | 28 +++++++++ lib/PHPExif/Mapper/Exiftool.php | 66 +++++++++++++++++++++ lib/PHPExif/Mapper/Native.php | 46 ++++++++++++++ tests/PHPExif/ExifTest.php | 2 + tests/PHPExif/Mapper/ExiftoolMapperTest.php | 2 + tests/PHPExif/Mapper/NativeMapperTest.php | 2 + 7 files changed, 152 insertions(+), 2 deletions(-) diff --git a/lib/PHPExif/Adapter/Exiftool.php b/lib/PHPExif/Adapter/Exiftool.php index d8f715b..f4eb648 100644 --- a/lib/PHPExif/Adapter/Exiftool.php +++ b/lib/PHPExif/Adapter/Exiftool.php @@ -100,12 +100,15 @@ public function getToolPath() */ public function getExifFromFile($file) { + $gpsFormat = '%d deg %d\' %.4f\"'; + $result = $this->getCliOutput( sprintf( - '%1$s%3$s -j %2$s', + '%1$s%3$s -j -c "%4$s" %2$s', $this->getToolPath(), $file, - $this->numeric ? ' -n' : '' + $this->numeric ? ' -n' : '', + $gpsFormat ) ); @@ -113,6 +116,7 @@ public function getExifFromFile($file) // map the data: $mapper = $this->getMapper(); + $mapper->setNumeric($this->numeric); $mappedData = $mapper->mapRawData(reset($data)); // hydrate a new Exif object diff --git a/lib/PHPExif/Exif.php b/lib/PHPExif/Exif.php index f9c2b2f..1ce5a5e 100755 --- a/lib/PHPExif/Exif.php +++ b/lib/PHPExif/Exif.php @@ -47,6 +47,7 @@ class Exif const TITLE = 'title'; const VERTICAL_RESOLUTION = 'verticalResolution'; const WIDTH = 'width'; + const GPS = 'gps'; /** * The mapped EXIF data @@ -808,4 +809,31 @@ public function setOrientation($value) return $this; } + + /** + * Returns GPS coordinates, if it exists + * + * @return array|boolean + */ + public function getGPS() + { + if (!isset($this->data[self::GPS])) { + return false; + } + + return $this->data[self::GPS]; + } + + /** + * Sets the GPS coordinates + * + * @param array $value + * @return \PHPExif\Exif + */ + public function setGPS(array $value) + { + $this->data[self::GPS] = $value; + + return $this; + } } diff --git a/lib/PHPExif/Mapper/Exiftool.php b/lib/PHPExif/Mapper/Exiftool.php index ddb6661..cc66335 100644 --- a/lib/PHPExif/Mapper/Exiftool.php +++ b/lib/PHPExif/Mapper/Exiftool.php @@ -50,6 +50,8 @@ class Exiftool implements MapperInterface const TITLE = 'Title'; const XRESOLUTION = 'XResolution'; const YRESOLUTION = 'YResolution'; + const GPSLATITUDEREF = 'GPSLatitudeRef'; + const GPSLONGITUDEREF = 'GPSLongitudeRef'; /** * Maps the ExifTool fields to the fields of @@ -84,8 +86,28 @@ class Exiftool implements MapperInterface self::YRESOLUTION => Exif::VERTICAL_RESOLUTION, self::IMAGEWIDTH => Exif::WIDTH, self::CAPTIONABSTRACT => Exif::CAPTION, + self::GPSLATITUDEREF => Exif::GPS, + self::GPSLONGITUDEREF => Exif::GPS, ); + /** + * @var bool + */ + protected $numeric = true; + + /** + * Mutator method for the numeric property + * + * @param bool $numeric + * @return \PHPExif\Mapper\Exiftool + */ + public function setNumeric($numeric) + { + $this->numeric = (bool)$numeric; + + return $this; + } + /** * Maps the array of raw source data to the correct * fields for the \PHPExif\Exif class @@ -96,6 +118,7 @@ class Exiftool implements MapperInterface public function mapRawData(array $data) { $mappedData = array(); + $gpsData = array(); foreach ($data as $field => $value) { if (!array_key_exists($field, $this->map)) { // silently ignore unknown fields @@ -122,12 +145,55 @@ public function mapRawData(array $data) $focalLengthParts = explode(' ', $value); $value = (int) reset($focalLengthParts); break; + case self::GPSLATITUDEREF: + $gpsData['lat'] = $this->extractGPSCoordinates($value); + break; + case self::GPSLONGITUDEREF: + $gpsData['lon'] = $this->extractGPSCoordinates($value); + break; } // set end result $mappedData[$key] = $value; } + // add GPS coordinates, if available + if (count($gpsData) === 2) { + $latitude = $gpsData['lat']; + $longitude = $gpsData['lon']; + + if ($latitude !== false && $longitude !== false) { + $gpsLocation = sprintf( + '%s,%s', + (strtoupper($data[self::GPSLATITUDEREF][0]) === 'S' ? -1 : 1) * $latitude, + (strtoupper($data[self::GPSLONGITUDEREF][0]) === 'W' ? -1 : 1) * $longitude + ); + + $key = $this->map[self::GPSLATITUDEREF]; + + $mappedData[$key] = $gpsLocation; + } + } + return $mappedData; } + + /** + * Extract GPS coordinates from formatted string + * + * @param string $coordinates + * @return array + */ + protected function extractGPSCoordinates($coordinates) + { + if ($this->numeric === true) { + return abs((float) $coordinates); + } else { + if (!preg_match('!^([0-9.]+) deg ([0-9.]+)\' ([0-9.]+)"!', $coordinates, $matches)) { + return false; + } + + return intval($matches[1]) + (intval($matches[2]) / 60) + (floatval($matches[3]) / 3600); + } + } } diff --git a/lib/PHPExif/Mapper/Native.php b/lib/PHPExif/Mapper/Native.php index 4b1c31b..8f93ce1 100644 --- a/lib/PHPExif/Mapper/Native.php +++ b/lib/PHPExif/Mapper/Native.php @@ -49,6 +49,8 @@ class Native implements MapperInterface const WIDTH = 'Width'; const XRESOLUTION = 'XResolution'; const YRESOLUTION = 'YResolution'; + const GPSLATITUDEREF = 'GPSLatitudeRef'; + const GPSLONGITUDEREF = 'GPSLongitudeRef'; const SECTION_FILE = 'FILE'; const SECTION_COMPUTED = 'COMPUTED'; @@ -107,6 +109,8 @@ class Native implements MapperInterface self::SOFTWARE => Exif::SOFTWARE, self::XRESOLUTION => Exif::HORIZONTAL_RESOLUTION, self::YRESOLUTION => Exif::VERTICAL_RESOLUTION, + self::GPSLATITUDEREF => Exif::GPS, + self::GPSLONGITUDEREF => Exif::GPS, ); /** @@ -119,6 +123,7 @@ class Native implements MapperInterface public function mapRawData(array $data) { $mappedData = array(); + $gpsData = array(); foreach ($data as $field => $value) { if ($this->isSection($field) && is_array($value)) { $subData = $this->mapRawData($value); @@ -157,12 +162,27 @@ public function mapRawData(array $data) $resolutionParts = explode('/', $value); $value = (int)reset($resolutionParts); break; + case self::GPSLATITUDEREF: + $gpsData['lat'] = $this->extractGPSCoordinate($value); + break; + case self::GPSLONGITUDEREF: + $gpsData['lon'] = $this->extractGPSCoordinate($value); + break; } // set end result $mappedData[$key] = $value; } + if (count($gpsData) === 2) { + $gpsLocation = sprintf( + '%s,%s', + (strtoupper($data[self::GPSLATITUDEREF][0]) === 'S' ? -1 : 1) * $gpsData['lat'], + (strtoupper($data[self::GPSLONGITUDEREF][0]) === 'W' ? -1 : 1) * $gpsData['lon'] + ); + $mappedData[Exif::GPS] = $gpsLocation; + } + return $mappedData; } @@ -176,4 +196,30 @@ protected function isSection($field) { return (in_array($field, $this->sections)); } + + /** + * Extract GPS coordinates from components array + * + * @param array $components + * @return float + */ + protected function extractGPSCoordinate(array $components) + { + $components = array_map(array($this, 'normalizeGPSComponent'), $components); + + return intval($components[0]) + (intval($components[1]) / 60) + (floatval($components[2]) / 3600); + } + + /** + * Normalize GPS coordinates components + * + * @param mixed $component + * @return int|float + */ + protected function normalizeGPSComponent($component) + { + $parts = explode('/', $component); + + return count($parts) === 1 ? $parts[0] : (int) reset($parts) / (int) end($parts); + } } diff --git a/tests/PHPExif/ExifTest.php b/tests/PHPExif/ExifTest.php index 06e19b8..06d34e9 100755 --- a/tests/PHPExif/ExifTest.php +++ b/tests/PHPExif/ExifTest.php @@ -549,6 +549,8 @@ public function testMutatorMethodsSetInProperty() break; case 'focalDistance': $setter = 'setFocusDistance'; + case 'gps': + break; default: $this->exif->$setter($expected); $propertyValue = $reflProp->getValue($this->exif); diff --git a/tests/PHPExif/Mapper/ExiftoolMapperTest.php b/tests/PHPExif/Mapper/ExiftoolMapperTest.php index 061872e..97fca37 100644 --- a/tests/PHPExif/Mapper/ExiftoolMapperTest.php +++ b/tests/PHPExif/Mapper/ExiftoolMapperTest.php @@ -47,6 +47,8 @@ public function testMapRawDataMapsFieldsCorrectly() unset($map[\PHPExif\Mapper\Exiftool::CREATEDATE]); unset($map[\PHPExif\Mapper\Exiftool::EXPOSURETIME]); unset($map[\PHPExif\Mapper\Exiftool::FOCALLENGTH]); + unset($map[\PHPExif\Mapper\Exiftool::GPSLATITUDEREF]); + unset($map[\PHPExif\Mapper\Exiftool::GPSLONGITUDEREF]); // create raw data $keys = array_keys($map); diff --git a/tests/PHPExif/Mapper/NativeMapperTest.php b/tests/PHPExif/Mapper/NativeMapperTest.php index 1f4e8de..b1d4882 100644 --- a/tests/PHPExif/Mapper/NativeMapperTest.php +++ b/tests/PHPExif/Mapper/NativeMapperTest.php @@ -47,6 +47,8 @@ public function testMapRawDataMapsFieldsCorrectly() unset($map[\PHPExif\Mapper\Native::FOCALLENGTH]); unset($map[\PHPExif\Mapper\Native::XRESOLUTION]); unset($map[\PHPExif\Mapper\Native::YRESOLUTION]); + unset($map[\PHPExif\Mapper\Native::GPSLATITUDEREF]); + unset($map[\PHPExif\Mapper\Native::GPSLONGITUDEREF]); // create raw data $keys = array_keys($map); From 1e2e623a2fffcf93e49299f1ce1ed1d383bca6d9 Mon Sep 17 00:00:00 2001 From: Tom Van Herreweghe Date: Fri, 3 Apr 2015 16:57:31 +0200 Subject: [PATCH 35/38] More unit tests for Exif (GPS added) Signed-off-by: Tom Van Herreweghe --- tests/PHPExif/ExifTest.php | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/tests/PHPExif/ExifTest.php b/tests/PHPExif/ExifTest.php index 06d34e9..1a3d741 100755 --- a/tests/PHPExif/ExifTest.php +++ b/tests/PHPExif/ExifTest.php @@ -128,6 +128,7 @@ public function testSetData() * @covers \PHPExif\Exif::getHeadline * @covers \PHPExif\Exif::getColorSpace * @covers \PHPExif\Exif::getOrientation + * @covers \PHPExif\Exif::getGPS * @param string $accessor */ public function testUndefinedPropertiesReturnFalse($accessor) @@ -171,6 +172,7 @@ public function providerUndefinedPropertiesReturnFalse() array('getHeadline'), array('getColorSpace'), array('getOrientation'), + array('getGPS'), ); } @@ -527,6 +529,7 @@ public function testGetGPS() * @covers \PHPExif\Exif::setHeadline * @covers \PHPExif\Exif::setColorSpace * @covers \PHPExif\Exif::setOrientation + * @covers \PHPExif\Exif::setGPS */ public function testMutatorMethodsSetInProperty() { @@ -547,10 +550,14 @@ public function testMutatorMethodsSetInProperty() $propertyValue = $reflProp->getValue($this->exif); $this->assertSame($now, $propertyValue[$value]); break; - case 'focalDistance': - $setter = 'setFocusDistance'; case 'gps': + $coords = '40.333452380556,-20.167314813889'; + $this->exif->$setter($coords); + $propertyValue = $reflProp->getValue($this->exif); + $this->assertEquals($expected, $propertyValue[$value]); break; + case 'focalDistance': + $setter = 'setFocusDistance'; default: $this->exif->$setter($expected); $propertyValue = $reflProp->getValue($this->exif); From 401686cce2af53ab06fc262f1c9cfde8cf8eedfc Mon Sep 17 00:00:00 2001 From: Tom Van Herreweghe Date: Fri, 3 Apr 2015 17:15:15 +0200 Subject: [PATCH 36/38] Unit tests for GPS stuff Signed-off-by: Tom Van Herreweghe --- lib/PHPExif/Exif.php | 4 +- lib/PHPExif/Mapper/Exiftool.php | 18 ++++---- lib/PHPExif/Mapper/Native.php | 16 +++---- tests/PHPExif/ExifTest.php | 3 +- tests/PHPExif/Mapper/ExiftoolMapperTest.php | 46 ++++++++++++++++++++- tests/PHPExif/Mapper/NativeMapperTest.php | 23 ++++++++++- 6 files changed, 86 insertions(+), 24 deletions(-) diff --git a/lib/PHPExif/Exif.php b/lib/PHPExif/Exif.php index 1ce5a5e..ba5080a 100755 --- a/lib/PHPExif/Exif.php +++ b/lib/PHPExif/Exif.php @@ -827,10 +827,10 @@ public function getGPS() /** * Sets the GPS coordinates * - * @param array $value + * @param string $value * @return \PHPExif\Exif */ - public function setGPS(array $value) + public function setGPS($value) { $this->data[self::GPS] = $value; diff --git a/lib/PHPExif/Mapper/Exiftool.php b/lib/PHPExif/Mapper/Exiftool.php index cc66335..62f838e 100644 --- a/lib/PHPExif/Mapper/Exiftool.php +++ b/lib/PHPExif/Mapper/Exiftool.php @@ -50,8 +50,8 @@ class Exiftool implements MapperInterface const TITLE = 'Title'; const XRESOLUTION = 'XResolution'; const YRESOLUTION = 'YResolution'; - const GPSLATITUDEREF = 'GPSLatitudeRef'; - const GPSLONGITUDEREF = 'GPSLongitudeRef'; + const GPSLATITUDE = 'GPSLatitude'; + const GPSLONGITUDE = 'GPSLongitude'; /** * Maps the ExifTool fields to the fields of @@ -86,8 +86,8 @@ class Exiftool implements MapperInterface self::YRESOLUTION => Exif::VERTICAL_RESOLUTION, self::IMAGEWIDTH => Exif::WIDTH, self::CAPTIONABSTRACT => Exif::CAPTION, - self::GPSLATITUDEREF => Exif::GPS, - self::GPSLONGITUDEREF => Exif::GPS, + self::GPSLATITUDE => Exif::GPS, + self::GPSLONGITUDE => Exif::GPS, ); /** @@ -145,10 +145,10 @@ public function mapRawData(array $data) $focalLengthParts = explode(' ', $value); $value = (int) reset($focalLengthParts); break; - case self::GPSLATITUDEREF: + case self::GPSLATITUDE: $gpsData['lat'] = $this->extractGPSCoordinates($value); break; - case self::GPSLONGITUDEREF: + case self::GPSLONGITUDE: $gpsData['lon'] = $this->extractGPSCoordinates($value); break; } @@ -165,11 +165,11 @@ public function mapRawData(array $data) if ($latitude !== false && $longitude !== false) { $gpsLocation = sprintf( '%s,%s', - (strtoupper($data[self::GPSLATITUDEREF][0]) === 'S' ? -1 : 1) * $latitude, - (strtoupper($data[self::GPSLONGITUDEREF][0]) === 'W' ? -1 : 1) * $longitude + (strtoupper($data['GPSLatitudeRef'][0]) === 'S' ? -1 : 1) * $latitude, + (strtoupper($data['GPSLongitudeRef'][0]) === 'W' ? -1 : 1) * $longitude ); - $key = $this->map[self::GPSLATITUDEREF]; + $key = $this->map[self::GPSLATITUDE]; $mappedData[$key] = $gpsLocation; } diff --git a/lib/PHPExif/Mapper/Native.php b/lib/PHPExif/Mapper/Native.php index 8f93ce1..ab68853 100644 --- a/lib/PHPExif/Mapper/Native.php +++ b/lib/PHPExif/Mapper/Native.php @@ -49,8 +49,8 @@ class Native implements MapperInterface const WIDTH = 'Width'; const XRESOLUTION = 'XResolution'; const YRESOLUTION = 'YResolution'; - const GPSLATITUDEREF = 'GPSLatitudeRef'; - const GPSLONGITUDEREF = 'GPSLongitudeRef'; + const GPSLATITUDE = 'GPSLatitude'; + const GPSLONGITUDE = 'GPSLongitude'; const SECTION_FILE = 'FILE'; const SECTION_COMPUTED = 'COMPUTED'; @@ -109,8 +109,8 @@ class Native implements MapperInterface self::SOFTWARE => Exif::SOFTWARE, self::XRESOLUTION => Exif::HORIZONTAL_RESOLUTION, self::YRESOLUTION => Exif::VERTICAL_RESOLUTION, - self::GPSLATITUDEREF => Exif::GPS, - self::GPSLONGITUDEREF => Exif::GPS, + self::GPSLATITUDE => Exif::GPS, + self::GPSLONGITUDE => Exif::GPS, ); /** @@ -162,10 +162,10 @@ public function mapRawData(array $data) $resolutionParts = explode('/', $value); $value = (int)reset($resolutionParts); break; - case self::GPSLATITUDEREF: + case self::GPSLATITUDE: $gpsData['lat'] = $this->extractGPSCoordinate($value); break; - case self::GPSLONGITUDEREF: + case self::GPSLONGITUDE: $gpsData['lon'] = $this->extractGPSCoordinate($value); break; } @@ -177,8 +177,8 @@ public function mapRawData(array $data) if (count($gpsData) === 2) { $gpsLocation = sprintf( '%s,%s', - (strtoupper($data[self::GPSLATITUDEREF][0]) === 'S' ? -1 : 1) * $gpsData['lat'], - (strtoupper($data[self::GPSLONGITUDEREF][0]) === 'W' ? -1 : 1) * $gpsData['lon'] + (strtoupper($data['GPSLatitudeRef'][0]) === 'S' ? -1 : 1) * $gpsData['lat'], + (strtoupper($data['GPSLongitudeRef'][0]) === 'W' ? -1 : 1) * $gpsData['lon'] ); $mappedData[Exif::GPS] = $gpsLocation; } diff --git a/tests/PHPExif/ExifTest.php b/tests/PHPExif/ExifTest.php index 1a3d741..964a917 100755 --- a/tests/PHPExif/ExifTest.php +++ b/tests/PHPExif/ExifTest.php @@ -552,9 +552,10 @@ public function testMutatorMethodsSetInProperty() break; case 'gps': $coords = '40.333452380556,-20.167314813889'; + $setter = 'setGPS'; $this->exif->$setter($coords); $propertyValue = $reflProp->getValue($this->exif); - $this->assertEquals($expected, $propertyValue[$value]); + $this->assertEquals($coords, $propertyValue[$value]); break; case 'focalDistance': $setter = 'setFocusDistance'; diff --git a/tests/PHPExif/Mapper/ExiftoolMapperTest.php b/tests/PHPExif/Mapper/ExiftoolMapperTest.php index 97fca37..3cff4d6 100644 --- a/tests/PHPExif/Mapper/ExiftoolMapperTest.php +++ b/tests/PHPExif/Mapper/ExiftoolMapperTest.php @@ -47,8 +47,8 @@ public function testMapRawDataMapsFieldsCorrectly() unset($map[\PHPExif\Mapper\Exiftool::CREATEDATE]); unset($map[\PHPExif\Mapper\Exiftool::EXPOSURETIME]); unset($map[\PHPExif\Mapper\Exiftool::FOCALLENGTH]); - unset($map[\PHPExif\Mapper\Exiftool::GPSLATITUDEREF]); - unset($map[\PHPExif\Mapper\Exiftool::GPSLONGITUDEREF]); + unset($map[\PHPExif\Mapper\Exiftool::GPSLATITUDE]); + unset($map[\PHPExif\Mapper\Exiftool::GPSLONGITUDE]); // create raw data $keys = array_keys($map); @@ -145,4 +145,46 @@ public function testMapRawDataCorrectlyFormatsFocalLength() $this->assertEquals(15, reset($mapped)); } + + /** + * @group mapper + * @covers \PHPExif\Mapper\Exiftool::mapRawData + */ + public function testMapRawDataCorrectlyFormatsGPSData() + { + $this->mapper->setNumeric(false); + $result = $this->mapper->mapRawData( + array( + 'GPSLatitude' => '40 deg 20\' 0.42857" N', + 'GPSLatitudeRef' => 'North', + 'GPSLongitude' => '20 deg 10\' 2.33333" W', + 'GPSLongitudeRef' => 'West', + ) + ); + + $expected = '40.333452380556,-20.167314813889'; + $this->assertCount(1, $result); + $this->assertEquals($expected, reset($result)); + } + + /** + * @group mapper + * @covers \PHPExif\Mapper\Exiftool::mapRawData + */ + public function testMapRawDataCorrectlyFormatsNumericGPSData() + { + $result = $this->mapper->mapRawData( + array( + 'GPSLatitude' => '40.333452381', + 'GPSLatitudeRef' => 'North', + 'GPSLongitude' => '20.167314814', + 'GPSLongitudeRef' => 'West', + ) + ); + + $expected = '40.333452381,-20.167314814'; + $this->assertCount(1, $result); + $this->assertEquals($expected, reset($result)); + } + } diff --git a/tests/PHPExif/Mapper/NativeMapperTest.php b/tests/PHPExif/Mapper/NativeMapperTest.php index b1d4882..d6e78fc 100644 --- a/tests/PHPExif/Mapper/NativeMapperTest.php +++ b/tests/PHPExif/Mapper/NativeMapperTest.php @@ -47,8 +47,8 @@ public function testMapRawDataMapsFieldsCorrectly() unset($map[\PHPExif\Mapper\Native::FOCALLENGTH]); unset($map[\PHPExif\Mapper\Native::XRESOLUTION]); unset($map[\PHPExif\Mapper\Native::YRESOLUTION]); - unset($map[\PHPExif\Mapper\Native::GPSLATITUDEREF]); - unset($map[\PHPExif\Mapper\Native::GPSLONGITUDEREF]); + unset($map[\PHPExif\Mapper\Native::GPSLATITUDE]); + unset($map[\PHPExif\Mapper\Native::GPSLONGITUDE]); // create raw data $keys = array_keys($map); @@ -168,4 +168,23 @@ public function testMapRawDataFlattensRawDataWithSections() ); $this->assertEquals($expected, $keys); } + + /** + * @group mapper + * @covers \PHPExif\Mapper\Native::mapRawData + */ + public function testMapRawDataCorrectlyFormatsGPSData() + { + $result = $this->mapper->mapRawData( + array( + 'GPSLatitude' => array('40/1', '20/1', '15/35'), + 'GPSLatitudeRef' => 'N', + 'GPSLongitude' => array('20/1', '10/1', '35/15'), + 'GPSLongitudeRef' => 'W', + ) + ); + + $expected = '40.333452380952,-20.167314814815'; + $this->assertEquals($expected, reset($result)); + } } From 1d4a96bcd49967ddeea90e30069962cda4bcbb5e Mon Sep 17 00:00:00 2001 From: Tom Van Herreweghe Date: Fri, 3 Apr 2015 18:00:59 +0200 Subject: [PATCH 37/38] Covered extra paths for Exiftool mapper test Signed-off-by: Tom Van Herreweghe --- lib/PHPExif/Mapper/Exiftool.php | 4 ++ tests/PHPExif/Mapper/ExiftoolMapperTest.php | 51 ++++++++++++++++++++- 2 files changed, 54 insertions(+), 1 deletion(-) diff --git a/lib/PHPExif/Mapper/Exiftool.php b/lib/PHPExif/Mapper/Exiftool.php index 62f838e..2be4c43 100644 --- a/lib/PHPExif/Mapper/Exiftool.php +++ b/lib/PHPExif/Mapper/Exiftool.php @@ -172,7 +172,11 @@ public function mapRawData(array $data) $key = $this->map[self::GPSLATITUDE]; $mappedData[$key] = $gpsLocation; + } else { + unset($mappedData[$this->map[self::GPSLATITUDE]]); } + } else { + unset($mappedData[$this->map[self::GPSLATITUDE]]); } return $mappedData; diff --git a/tests/PHPExif/Mapper/ExiftoolMapperTest.php b/tests/PHPExif/Mapper/ExiftoolMapperTest.php index 3cff4d6..485cda8 100644 --- a/tests/PHPExif/Mapper/ExiftoolMapperTest.php +++ b/tests/PHPExif/Mapper/ExiftoolMapperTest.php @@ -186,5 +186,54 @@ public function testMapRawDataCorrectlyFormatsNumericGPSData() $this->assertCount(1, $result); $this->assertEquals($expected, reset($result)); } - + + /** + * @group mapper + * @covers \PHPExif\Mapper\Exiftool::mapRawData + */ + public function testMapRawDataCorrectlyIgnoresIncorrectGPSData() + { + $this->mapper->setNumeric(false); + $result = $this->mapper->mapRawData( + array( + 'GPSLatitude' => '40.333452381', + 'GPSLatitudeRef' => 'North', + 'GPSLongitude' => '20.167314814', + 'GPSLongitudeRef' => 'West', + ) + ); + + $this->assertCount(0, $result); + } + + /** + * @group mapper + * @covers \PHPExif\Mapper\Exiftool::mapRawData + */ + public function testMapRawDataCorrectlyIgnoresIncompleteGPSData() + { + $result = $this->mapper->mapRawData( + array( + 'GPSLatitude' => '40.333452381', + 'GPSLatitudeRef' => 'North', + ) + ); + + $this->assertCount(0, $result); + } + + /** + * @group mapper + * @covers \PHPExif\Mapper\Exiftool::setNumeric + */ + public function testSetNumericInProperty() + { + $reflProperty = new \ReflectionProperty(get_class($this->mapper), 'numeric'); + $reflProperty->setAccessible(true); + + $expected = true; + $this->mapper->setNumeric($expected); + + $this->assertEquals($expected, $reflProperty->getValue($this->mapper)); + } } From ff651832f57185617219f11e370bfbd0e59aff3d Mon Sep 17 00:00:00 2001 From: Tom Van Herreweghe Date: Sat, 4 Apr 2015 13:03:12 +0200 Subject: [PATCH 38/38] New info in CHANGELOG & README Signed-off-by: Tom Van Herreweghe --- CHANGELOG.rst | 10 ++++++++++ README.md | 6 ++++-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index eb09883..2059618 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,6 +1,15 @@ CHANGELOG ===== +0.4.0 +----- + +* Improvement `#25`_: Extracted mapping logic into separate classes +* Added ``GPS`` information +* Improved unit tests; coverage up to 100% +* Added contributor to README.md +* Added extra stuff about unit tests to the ``Contributing`` section of the README.md + 0.3.0 ----- @@ -12,6 +21,7 @@ CHANGELOG * Composer.json: added semver version for phpmd; removed pdepend * added ``Orientation``, ``MimeType``, ``FileSize`` and ``ColorSpace`` options to EXIF +.. _`#25`: https://github.com/Miljar/php-exif/issues/25 .. _`#24`: https://github.com/Miljar/php-exif/issues/24 .. _`#18`: https://github.com/Miljar/php-exif/issues/18 .. _`#15`: https://github.com/Miljar/php-exif/issues/15 diff --git a/README.md b/README.md index 5ab0451..fbcf662 100755 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# [PHPExif v0.3.0](http://github.com/Miljar/php-exif) [![Build Status](https://travis-ci.org/Miljar/php-exif.png?branch=master)](https://travis-ci.org/Miljar/php-exif) [![Coverage Status](https://coveralls.io/repos/Miljar/php-exif/badge.svg?branch=master)](https://coveralls.io/r/Miljar/php-exif?branch=master) [![Code Climate](https://codeclimate.com/github/Miljar/php-exif/badges/gpa.svg)](https://codeclimate.com/github/Miljar/php-exif) +# [PHPExif v0.4.0](http://github.com/Miljar/php-exif) [![Build Status](https://travis-ci.org/Miljar/php-exif.png?branch=master)](https://travis-ci.org/Miljar/php-exif) [![Coverage Status](https://coveralls.io/repos/Miljar/php-exif/badge.svg?branch=master)](https://coveralls.io/r/Miljar/php-exif?branch=master) [![Code Climate](https://codeclimate.com/github/Miljar/php-exif/badges/gpa.svg)](https://codeclimate.com/github/Miljar/php-exif) PHPExif is a library which gives you easy access to the EXIF meta-data of an image. @@ -12,7 +12,7 @@ PHPExif serves as a wrapper around some native or CLI tools which access this EX ## Installation (composer) ```json -"miljar/php-exif": "~0.3.0" +"miljar/php-exif": "~0.4.0" ``` @@ -27,6 +27,7 @@ PHPExif serves as a wrapper around some native or CLI tools which access this EX Please submit all pull requests against the correct branch. The release branch for the next version is a branch with the same name as the next version. Bugfixes should go in the master branch, unless they are for code in a new release branch. PHPExif is written according the [PSR-0/1/2 standards](http://www.php-fig.org/). When submitting code, please make sure it is conform these standards. +We aim to have all functionality covered by unit tests. When submitting code, you are strongly encouraged to unit test your code and to keep the level of code coverage on par with the current level. All contributions are welcomed and greatly appreciated. @@ -40,6 +41,7 @@ Have a bug or a feature request? [Please open a new issue](https://github.com/Mi * [Ingewikkeld](https://github.com/Ingewikkeld) * [Christophe Singer](https://github.com/wasinger) * [Hanov Ruslan](https://github.com/hanovruslan) +* [Julian Gutierrez](https://github.com/juliangut) ## License