Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Adding first stub of sub-path matchers
- Loading branch information
Showing
5 changed files
with
340 additions
and
0 deletions.
There are no files selected for viewing
79 changes: 79 additions & 0 deletions
79
src/ZfrRest/Mvc/Router/Http/Matcher/AssociationSubPathMatcher.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
<?php | ||
/* | ||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
* | ||
* This software consists of voluntary contributions made by many individuals | ||
* and is licensed under the MIT license. | ||
*/ | ||
|
||
namespace ZfrRest\Mvc\Router\Http\Matcher; | ||
|
||
use Doctrine\Common\Collections\Criteria; | ||
use Zend\Http\Request; | ||
use ZfrRest\Mvc\Exception; | ||
use ZfrRest\Mvc\Exception\RuntimeException; | ||
use ZfrRest\Resource\Resource; | ||
use ZfrRest\Resource\ResourceInterface; | ||
|
||
/** | ||
* {@inheritDoc} | ||
* | ||
* @license MIT | ||
* @author Marco Pivetta <ocramius@gmail.com> | ||
*/ | ||
class AssociationSubPathMatcher implements SubPathMatcherInterface | ||
{ | ||
public function matchSubPath( | ||
ResourceInterface $resource, | ||
$subPath, | ||
Request $request | ||
) { | ||
if ($resource->isCollection()) { | ||
return null; | ||
} | ||
|
||
$data = $resource->getData(); | ||
|
||
// @todo cannot handle non-object resources because of this hardcoding | ||
if (! is_object($data)) { | ||
return null; | ||
} | ||
|
||
$resourceMetadata = $resource->getMetadata(); | ||
$associationName = array_shift(explode('/', trim($subPath, '/'))); | ||
|
||
if (! $resourceMetadata->hasAssociation($associationName)) { | ||
return null; | ||
} | ||
|
||
$classMetadata = $resourceMetadata->getClassMetadata(); | ||
$reflectionClass = $classMetadata->getReflectionClass(); | ||
// @todo Using reflection directly? Maybe should be coded in the metadata interface instead? | ||
$reflectionProperty = $reflectionClass->getProperty($associationName); | ||
$associationMetadata = $resourceMetadata->getAssociationMetadata($associationName); | ||
|
||
$reflectionProperty->setAccessible(true); | ||
|
||
$associationData = $reflectionProperty->getValue($data); | ||
|
||
// @todo null and scalars won't work as a resource here! | ||
if (! $associationMetadata->getClassMetadata()->getReflectionClass()->isInstance($associationData)) { | ||
return null; | ||
} | ||
|
||
return new SubPathMatch( | ||
new Resource($associationData, $associationMetadata), | ||
substr($subPath, strpos($subPath, $associationName), strlen($associationName)) | ||
); | ||
} | ||
} |
71 changes: 71 additions & 0 deletions
71
src/ZfrRest/Mvc/Router/Http/Matcher/BaseSubPathMatcher.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
<?php | ||
/* | ||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
* | ||
* This software consists of voluntary contributions made by many individuals | ||
* and is licensed under the MIT license. | ||
*/ | ||
|
||
namespace ZfrRest\Mvc\Router\Http\Matcher; | ||
|
||
use Doctrine\Common\Collections\Criteria; | ||
use Zend\Http\Request; | ||
use ZfrRest\Mvc\Exception; | ||
use ZfrRest\Mvc\Exception\RuntimeException; | ||
use ZfrRest\Resource\ResourceInterface; | ||
|
||
/** | ||
* {@inheritDoc} | ||
* | ||
* Base sub-path matcher - passes the sub-path to either an association or | ||
* a collection matcher depending on the case | ||
* | ||
* @license MIT | ||
* @author Marco Pivetta <ocramius@gmail.com> | ||
*/ | ||
class BaseSubPathMatcher implements SubPathMatcherInterface | ||
{ | ||
public function __construct() | ||
{ | ||
$this->collectionMatcher = new CollectionSubPathMatcher(); | ||
$this->associationMatcher = new AssociationSubPathMatcher(); | ||
} | ||
|
||
public function matchSubPath( | ||
ResourceInterface $resource, | ||
$subPath, | ||
Request $request | ||
) { | ||
$path = trim($subPath, '/'); | ||
|
||
if (empty($path)) { | ||
return new SubPathMatch($resource, $subPath); | ||
} | ||
|
||
if ($resource->isCollection()) { | ||
$match = $this->collectionMatcher->matchSubPath($resource, $path, $request); | ||
} else { | ||
$match = $this->associationMatcher->matchSubPath($resource, $path, $request); | ||
} | ||
|
||
if (! $match) { | ||
return null; | ||
} | ||
|
||
return $this->matchSubPath( | ||
$match->matchedResource, | ||
substr($path, strlen($match->matchedPath)), | ||
$request | ||
); | ||
} | ||
} |
100 changes: 100 additions & 0 deletions
100
src/ZfrRest/Mvc/Router/Http/Matcher/CollectionSubPathMatcher.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
<?php | ||
/* | ||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
* | ||
* This software consists of voluntary contributions made by many individuals | ||
* and is licensed under the MIT license. | ||
*/ | ||
|
||
namespace ZfrRest\Mvc\Router\Http\Matcher; | ||
|
||
use Doctrine\Common\Collections\ArrayCollection; | ||
use Doctrine\Common\Collections\Criteria; | ||
use Doctrine\Common\Collections\Selectable; | ||
use Zend\Http\Request; | ||
use Zend\Stdlib\ArrayUtils; | ||
use ZfrRest\Mvc\Exception; | ||
use ZfrRest\Mvc\Exception\RuntimeException; | ||
use ZfrRest\Resource\Resource; | ||
use ZfrRest\Resource\ResourceInterface; | ||
|
||
/** | ||
* {@inheritDoc} | ||
* | ||
* @license MIT | ||
* @author Marco Pivetta <ocramius@gmail.com> | ||
*/ | ||
class CollectionSubPathMatcher implements SubPathMatcherInterface | ||
{ | ||
public function matchSubPath( | ||
ResourceInterface $resource, | ||
$subPath, | ||
Request $request | ||
) { | ||
if (! $resource->isCollection()) { | ||
return null; | ||
} | ||
|
||
$path = trim($subPath, '/'); | ||
|
||
if (empty($path)) { | ||
return new SubPathMatch($this->filterAssociation($resource, $request), $subPath); | ||
} | ||
|
||
$identifier = array_shift(explode('/', trim($subPath, '/'))); | ||
$classMetadata = $resource->getMetadata()->getClassMetadata(); | ||
$data = $this->findItem($resource->getData(), $classMetadata->getIdentifierFieldNames(), $identifier); | ||
|
||
if (null === $data) { | ||
// @todo is a null value actually valid? | ||
return null; | ||
} | ||
|
||
return new SubPathMatch( | ||
new Resource($data, $resource->getMetadata()), | ||
substr($subPath, strpos($subPath, $identifier), strlen($identifier)) | ||
); | ||
} | ||
|
||
protected function findItem($data, array $identifierNames, $identifier) | ||
{ | ||
if (count($identifierNames) > 1) { | ||
// @todo Cannot match multiple identifiers for now | ||
return null; | ||
} | ||
|
||
if (!$data instanceof Selectable) { | ||
if (! ($data instanceof \Traversable || is_array($data))) { | ||
// @todo cannot match on non-selectables? | ||
return null; | ||
} | ||
|
||
$data = new ArrayCollection(ArrayUtils::iteratorToArray($data)); | ||
} | ||
|
||
if (! $data instanceof Selectable) { | ||
// @todo should probably also handle repositories with no Selectable API | ||
return null; | ||
} | ||
|
||
return $data->matching( | ||
new Criteria(Criteria::expr()->eq(current($identifierNames), $identifier)) | ||
)->first(); | ||
} | ||
|
||
protected function filterAssociation(ResourceInterface $resource, Request $request) | ||
{ | ||
// @todo add collection filtering via GET parameters | ||
return $resource; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
<?php | ||
/* | ||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
* | ||
* This software consists of voluntary contributions made by many individuals | ||
* and is licensed under the MIT license. | ||
*/ | ||
|
||
namespace ZfrRest\Mvc\Router\Http\Matcher; | ||
|
||
use Doctrine\Common\Collections\Criteria; | ||
use Zend\Http\Request; | ||
use ZfrRest\Mvc\Exception; | ||
use ZfrRest\Mvc\Exception\RuntimeException; | ||
use ZfrRest\Resource\ResourceInterface; | ||
|
||
/** | ||
* {@inheritDoc} | ||
* | ||
* @license MIT | ||
* @author Marco Pivetta <ocramius@gmail.com> | ||
*/ | ||
class SubPathMatch | ||
{ | ||
public $matchedPath; | ||
public $matchedResource; | ||
|
||
public function __construct(ResourceInterface $matchedResource = null, $matchedPath = null) | ||
{ | ||
$this->matchedResource = $matchedResource; | ||
$this->matchedPath = $matchedPath; | ||
} | ||
} |
47 changes: 47 additions & 0 deletions
47
src/ZfrRest/Mvc/Router/Http/Matcher/SubPathMatcherInterface.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
<?php | ||
/* | ||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
* | ||
* This software consists of voluntary contributions made by many individuals | ||
* and is licensed under the MIT license. | ||
*/ | ||
|
||
namespace ZfrRest\Mvc\Router\Http\Matcher; | ||
|
||
use Doctrine\Common\Collections\Criteria; | ||
use Zend\Http\Request; | ||
use ZfrRest\Mvc\Exception; | ||
use ZfrRest\Mvc\Exception\RuntimeException; | ||
use ZfrRest\Resource\ResourceInterface; | ||
|
||
/** | ||
* Association matcher - builds a resource from a given resource and an association | ||
* | ||
* @license MIT | ||
* @author Marco Pivetta <ocramius@gmail.com> | ||
*/ | ||
interface SubPathMatcherInterface | ||
{ | ||
/** | ||
* @param ResourceInterface $resource | ||
* @param $subPath | ||
* @param Request $request | ||
* | ||
* @return SubPathMatch|null | ||
*/ | ||
public function matchSubPath( | ||
ResourceInterface $resource, | ||
$subPath, | ||
Request $request | ||
); | ||
} |