【问题标题】:Custom method annotation with parameter insertion symfony 3.2带有参数插入的自定义方法注释 symfony 3.2
【发布时间】:2017-08-11 10:39:24
【问题描述】:

因此,我们的目标是制作自定义注释,该注释也可以将参数插入方法中。因此,经过数小时寻找解决方案并尝试使其发挥作用后,我从未找到完整的解决方案,因此我将一些我能找到的东西放在一起,我的代码如下所示:

public function onKernelController(FilterControllerEvent $event)
{
    if (!is_array($controller = $event->getController())){
        return;
    }

    $request = $event->getRequest();
    $content = $request->getContent();
    $data = json_decode($content,true);

    $reflectionObject = new \ReflectionObject($controller[0]);
    $reflectionMethod = $reflectionObject->getMethod($controller[1]);
    $methodAnnotation = $this->reader->getMethodAnnotation($reflectionMethod, CheckRequest::class);
    if(!$methodAnnotation){
        return;
    }
    $propertyName = $methodAnnotation->getName();

    try{
        if ($request->getContentType() !== 'json' ) {
            throw new ControlerNotAvailableException();
        }

        if(empty($content)){
            throw new ControlerNotAvailableException();
        }

        if(empty($data) || !array_key_exists('type', $data)) {
            throw new ControlerNotAvailableException();
        }
    }catch(ControlerNotAvailableException $e){
    }

    foreach($reflectionMethod->getParameters() as $param){
        if($param->getName() !== $propertyName){
            continue;
        }
        if($request->attributes->has($propertyName)){
            return;
        }
        $request->attributes->set($propertyName, $data);
    }
}

我的注释类看起来像这样:

class CheckRequest
{
private $name;

public function __construct($options)
{
    if(isset($options['value'])){
        $options['name'] = $options['value'];
        unset($options['value']);
    }
    foreach ($options as $key => $value){
        if(!property_exists($this, $key)){
            throw new \InvalidArgumentException(sprintf('Property %s does not exist', $key));
        }
        $this->$key = $value;
    }
}


/**
 * @return mixed
 */
public function getName()
{
    return $this->name;
}

/**
 * @param mixed $name
 */
public function setName($name)
{
    $this->name = $name;
}
}

所以为了让这件事更清楚一点。我有一个监听器事件,它监听 kernel.controller 事件。在那个侦听器中,我正在运行一些小问题,例如内容类型是否为 json 等...此外,ControllerNotAvailableEception 是我制作的自定义异常,所以不要让您感到困惑。然后我们进入我的问题所在的部分,即以下内容:

foreach($reflectionMethod->getParameters() as $param){
    if($param->getName() !== $propertyName){
        continue;
    }
    if($request->attributes->has($propertyName)){
        return;
    }
    $request->attributes->set($propertyName, $data);
}

现在,只是为了澄清一下,这是可行的,并且可以正确地在方法参数中注入值,所以如果我在我的控制器中输入这样的内容:

/**
 *@CheckRequest(name = "data")
*/
 public function createAction(array $data){
 }

这行得通,并且填充了 $data 参数。 最后,当我解释了这一切时,我现在可以问我的问题了。 这是执行此操作的正确方法,还是有一些通过注释注入参数值的“标准化”方法,您能给我举个例子吗?我知道@ParamConverter 注释做了这些事情,但我不知道它是如何将值绑定到引擎盖下的参数的。 提前感谢您的回答!

【问题讨论】:

  • 尝试编辑您的问题,以便简短地说出您想要实现的目标。特别是这些参数是什么以及为什么要注入它们。这将增加您获得有用答案的机会。
  • 您好,感谢您的建议。我想注入参数的原因是我可以减少控制器中的冗余,假设我有 5 个控制器,在这些控制器中,第一行代码是 $data = json_decode($request->getContent( ));所以我不想每次在我的请求中得到一个 Json 时都写那行代码。我想自动将它绑定到方法的参数。我希望这能澄清我的意图:)
  • 你说“这行得通”。你真的试过了吗?乍一看,这似乎不像你拥有的那样工作。
  • 是的,我试过了,它工作正常。对不起我生疏的英语。你能告诉我其他更合适的方法吗?

标签: php symfony annotations doctrine


【解决方案1】:

我认为与必须指定参数并将其传递给每个函数相比,您可以更简洁地执行此操作。我会考虑制作一个扩展基本 Controller 的 Controller 类,并在其中有一个 $data 变量。例如:

基本控制器

namespace AppBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;

class JsonRequestController extends Controller
{
    /**
     * @ var array
     */
    private $data;

    /**
     * @return array
     */
    public function getData()
    {
        return $this->data;
    }

    /**
     * @param array $data
     */
    public function setData(array $data)
    {
        $this->data= $data;
    }
}

然后让您的侦听器仅在您位于 JsonRequestController 的实例中并且设置了注释时执行您的检查。您将填充 $data 值。

监听器

public function onKernelController(FilterControllerEvent $event)
{
    if (!is_array($controller = $event->getController())) {
        return;
    }

    if (!$controller[0] instanceof JsonRequestController) {
        return;
    }

    // ...

    $controller[0]->setData(json_decode($content, true));

    // ..
}

带注释的控制器

/**
 * @CheckRequest(name = "data")
 */
public function createAction()
{
    // access via $this->getData()
}

这将使事情变得简单,然后如果您需要扩展功能,您可以 - 比如有多个不同的变量,您将参数传递到您的注释中,或者使用 protected 而不是 private 并访问 @987654328直接@变量等

【讨论】:

  • 嗯,这对我的问题来说是一个非常巧妙的解决方案。我将尝试在我的应用程序中实现这一点,代码简洁易懂。再次感谢杰森的帮助。 :)
猜你喜欢
  • 2015-05-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-11-05
  • 1970-01-01
相关资源
最近更新 更多