Dua*_*ran 6 php doctrine-orm symfony-2.1
我正在使用Symfony 2.1应用程序,我有很多参数通过POST请求发送,我正在寻找一种更智能的方法来获取每个请求参数并填充我的实体类.我希望避免$entity->setMyParam($my_param)为n请求参数编写表达式.例如,这是我的实体的片段:
namespace Brea\ApiBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
/**
* Brea\ApiBundle\Entity\Distributions
*
* @ORM\Table(name="distributions")
* @ORM\Entity
*/
class Distributions
{
/**
* @var string $recordType
*
* @ORM\Column(name="record_type", type="string", nullable=false)
* @Assert\NotBlank()
* @Assert\Choice(choices = {"a", "b", "c", "d", "e"}, message = "Choose a valid record type")
*/
private $recordType;
/**
* Set recordType
*
* @param string $recordType
*/
public function setRecordType($recordType)
{
$this->recordType = $recordType;
}
/**
* Get recordType
*
* @return string
*/
public function getRecordType()
{
return $this->recordType;
}
}
Run Code Online (Sandbox Code Playgroud)
我的控制器尝试接受每个请求,查看参数并将请求参数的值设置为实体:
public function createRecordAction(Request $request, $id)
{
$distribution = new Distributions();
$params = $request->request;
foreach ($request->request->all() as $param=>$value)
{
if ($param == "_method")
continue;
$function = "set".str_replace(' ','',ucwords(preg_replace('/[^A-Z^a-z^0-9]+/',' ',$param)));
$distribution->$function($value);
}
}
Run Code Online (Sandbox Code Playgroud)
它有效,但我对这种方法的不满是我需要在每个执行类似操作的控制器中运行此代码.我可以将它重构为父类,作为避免重复代码的方法,但我很好奇这是否是一个好习惯.我在Symfony框架中寻找了一些已经完成此任务的东西,但我能找到的只是将请求绑定到表单的示例.
首先:警告!!
正如我之前评论的那样,我会非常小心地使用原始帖子中提供的代码,因为您说它是来自请求的数据POST,这意味着客户端可以在其中注入任何类型的数据并调用您可能不需要的函数对象(或者通过向您发送不存在的函数名称而导致脚本失败)。
我实际上会先读结论..!:) 然后回到 Alt。1 和 2。
替代方案 1:
话虽如此,问题的另一种解决方案是赋予对象获取自己数据的责任。有了足够细化的对象,您就不应该得到臃肿的代码,并且您可以在每个类中定义要查找的参数以及要调用的函数(并在对类进行更改时本地化更改):
class BookInformation{
private $publisher;
private $name;
private $price;
public static createFromRequest($req){
$publisher = Publisher::createFromRequest($req);
$book = new BookInformation($publisher, $req['book_name'], $req['book_price']);
$book->setABC($req['abc']);
//...
return $book;
}
public __construct($publisher, $name, $price){
//...
}
}
class Publisher{
private $name;
private $address;
public static createFromRequest($req){
return new Publisher($req['publisher_name'], $req['publisher_address']);
}
public __construct($name, $address){
//...
}
}
Run Code Online (Sandbox Code Playgroud)
正如我之前所说,此方法的一大优点是,如果您需要向任何这些类添加新属性,则根本不必编辑控制器,只需编辑“从请求方法初始化”即可。未来的更改将本地化到修改后的类。
当然,不要忘记验证从用户请求发送的任何数据(但这只是常识)。
替代方案 2:
请注意,第一个替代方案与工厂模式(基于 GoF 的抽象工厂)非常相似,您也可以使用该模式实现解决方案:
class BookFactory{
public createBookInformation($req){
$publisher = $this->createPublisher($req);
$book = new BookInformation($publisher, $req['book_name'], $req['book_price']);
$book->setABC($req['abc']);
//...
return $book;
}
public createPublisher($req){
return new Publisher($req['publisher_name'], $req['publisher_address']);
}
//createAnythingRelatedToBooks($req)...
}
Run Code Online (Sandbox Code Playgroud)
这样,您就可以将所有初始化过程放在一个非常有凝聚力的类中,该类的唯一职责是根据请求对象初始化某个对象系列(这是一件非常好的事情)。但是,如果您向这些类之一添加属性,则还必须编辑适当的工厂方法。
结论
请注意,这两种替代方案实际上并不是真正的替代方案...它们可以与您的初始代码(尤其是工厂代码)一起使用。它们实际上只解决了您的最后一个问题(“将代码放在哪里”问题)。
然而,即使您确实清理了POST请求并且仅调用带注释的函数(如前所述),我也不会真正建议它,因为我感觉更复杂的业务规则会很快破坏设计(但也许您'已经全部涵盖了(?))。也就是说,我认为您无法轻松地在初始化过程中插入业务规则,因为它是自动的(它无法对值进行任何验证,因为它可以是任何类型的值)并且我觉得您会初始化后最终会“撤消”东西(我个人讨厌......有很多错误的空间)!
例如,参加替代方案 1中相同的两门课程(BookInformation和Publisher)。
假设 aBook只能有 a ,Publisher前提是它Publisher已在数据库中注册并且其地址已得到确认(新出版商需要使用另一个界面创建,然后在链接到图书之前确认其地址)。
否则,无论请求数据如何,publisher都应设置为 XYZ。我有一种感觉(我可能是错的),为了支持这些类型的规则,您必须实际构造对象(自动),然后publisher在属性与某些规则不匹配时销毁/重新分配该属性。现在,如果内存中有这些Publisher对象的池,您还需要记住删除Publisher该池中错误创建的对象。这只是一条规则!
您可以使用代码来“修复”该问题的一件事是为每个 setter (validXYZ()) 提供一个验证方法,但这开始看起来像是一种设计,如果验证依赖于其他方法,那么它很快就会崩溃。对象/数据...
我真的没有什么其他事情可以阻止您使用该代码,但如果您这样做,请让我们了解一两年后它的工作原理(一旦添加了一些维护/新功能等)。 .)。
| 归档时间: |
|
| 查看次数: |
2374 次 |
| 最近记录: |