AOEpeople / TYPO3_Restler

restler (PHP REST-Framework) for TYPO3
GNU General Public License v3.0
30 stars 17 forks source link

Route does not matches when there is only a detail route #40

Closed develth closed 4 years ago

develth commented 4 years ago

Hi,

i just started using this extension - thanks for the great work!

My current setup is TYPO3 9.5 and i´m on branch feature/typo3-9-support

Currently i just have a Controller that outputs a array - it worked:

/**
 * Get Items
 *
 * @url GET test
 * @return array
 */
 public function getItems()
 {
   $arr = array();
   for($i = 0; $i < 20; $i++){
     $arr[] = 'item'.$i;
   }
   return $arr;
 }

Everything worked fine. After that i tried to use parameter:

/**
 * Get Items
 *
 * @url GET test/{count}
 * @param integer $count
 * @return array
 */
 public function getItems($count)
 {
  $arr = array();
   for($i = 0; $i < $count; $i++){
     $arr[] = 'item'.$i;
   }
   return $arr;
 }

It resulted in an error. I started debugging and recognized that $this->isRestlerUrl in the Dispatcher will fail. After going into the function, i recognized that it tries to strpos /api/test/20with api/test/{count}, what fails. If i add a default function (GET or POST ) with only @url GET test the call with the parameter works.

IMHO there is missing a way that checks if a parameter URL is valid, too

Thanks & best regards Thomas

tomasnorre commented 4 years ago

Thanks for you report, would it be possible for you to add a Pull Request for that branch ?

develth commented 4 years ago

I will think about a possible and efficient solution and create a PR

sven-carstens commented 4 years ago

How do you register your controller?

We add our controllers via $restler->addAPIClass

$restler->addAPIClass(ProductController::class, 'api/products');

And inside of the controller we use the placeholders inside of the urls.

@url GET {productId} for the details.

@url GET for the overview.

develth commented 4 years ago

I registered the Controller the same way you did.

What happens if you disable your overview route? Does the detail action still works?

sven-carstens commented 4 years ago

Could you try this replacement for isRestlerUrl in restler/Classes/System/Dispatcher.php

`

private function isRestlerUrl($uri)
{
    foreach (Routes::findAll() as $routes) {
        foreach ($routes as $route) {
            $routeMatcher = '/^' . preg_quote('/' . rtrim($route['route']['url'], '/*'), '/') . '/';

            if (is_array($route['route']['arguments'])) {
                foreach ($route['route']['arguments'] as $argumentName => $argumentNumber) {
                    $metadataType = $route['route']['metadata']['param'][$argumentNumber];

                    $argumentReplace = '[^\/]+';

                    switch ($metadataType['type']) {
                        case 'integer':
                            $argumentReplace = '[\d]+';
                            break;
                    }

                    $routeMatcher = str_replace(
                        preg_quote('{' . $argumentName . '}', '/'),
                        $argumentReplace,
                        $routeMatcher
                    );
                }
            }
            if (preg_match($routeMatcher, $uri) === 1) {
                return true;
            }
        }
    }

    return false;
}

`

develth commented 4 years ago

No change when only edited in Dispatcher.php on the v9 Branch, but changed it in "RestlerEnhancer.php", too - it worked!

Only RestlerEnhancer.php will also fail.

sven-carstens commented 4 years ago

If updated both code parts to one common code base and added the preg_match matching.

e8f029427486657cbddbf355761d4d01fedabd09

develth commented 4 years ago

Should be fixed. Thanks!