Php Zend_Db_为更新/删除查询选择

Php Zend_Db_为更新/删除查询选择,php,mapping,zend-framework,Php,Mapping,Zend Framework,在处理应用程序的映射结构时,我们遇到了一些代码一致性方面的问题。虽然使用Zend_Db_select类和诸如:$select->from'table'->where'id=?,1这样的函数进行select查询很容易,但它不适用于更新/删除查询。没有像Zend_Db_Update或Zend_Db_Delete这样的类来构建更新和删除查询,就像构建选择查询一样。为了解决这个问题,我们扩展了Zend_Db_Select类,如下面的代码所示。代码显示了扩展Zend_Db_Select类的自定义类,在底部

在处理应用程序的映射结构时,我们遇到了一些代码一致性方面的问题。虽然使用Zend_Db_select类和诸如:$select->from'table'->where'id=?,1这样的函数进行select查询很容易,但它不适用于更新/删除查询。没有像Zend_Db_Update或Zend_Db_Delete这样的类来构建更新和删除查询,就像构建选择查询一样。为了解决这个问题,我们扩展了Zend_Db_Select类,如下面的代码所示。代码显示了扩展Zend_Db_Select类的自定义类,在底部显示了一些最小的示例代码,以显示如何使用它

<?php
class Unica_Model_Statement extends Zend_Db_Select
{
    public function __construct($oMapper)
    {
        parent::__construct($oMapper->getAdapter());
        $this->from($oMapper->getTableName());
    }


    /**
     * @desc Make a string that can be used for updates and delete
     *       From the string "SELECT `column` FROM `tabelnaam` WHERE `id` = 1" only the part "`id = `" is returned. 
     * @return string 
     */
    public function toAltString()
    {
        $sQuery = $this->assemble();        // Get the full query string
        $sFrom = $this->_renderFrom('');    // Get the FROM part of the string

        // Get the text after the FROM (and therefore not using the "SELECT `colname`" part)
        $sString = strstr($sQuery,$sFrom);

        // Delete the FROM itself from the query (therefore deleting the "FROM `tabelnaam`" part)
        $sString = str_replace($sFrom, '', $sString);

        // Delete the word "WHERE" from the string.
        $sString = str_replace('WHERE', '', $sString);

        return $sString;
    }
}

################################################
# Below code is just to demonstrate the usage. #
################################################

class Default_IndexController extends Zend_Controller_Action
{
    public function indexAction()
    {
        $person = new Unica_Model_Person_Entity();
        $statement = new Unica_Model_Statement($person->getMapper());
        $statement->where('id = ?' , 1);
        $person->getMapper()->delete($statement);
    }
}

class Unica_Model_Person_Mapper
{
    public function delete($statement)
    {
        $where = $statement->toAltString();
        $this->getAdapter()->delete($this->_tableName,$where);
    }
}
使用这个类一切都很好,但它让我们怀疑我们是否遗漏了什么。有没有一个原因没有像select那样的默认更新/删除类,并且在其他地方使用这个类会给我们带来麻烦

如蒙指教,不胜感激。 提前感谢,


伊利亚人

我不知道Zend_Db_Select不提供CUD方法的确切原因。显而易见的解释是,Select意味着您应该将其用于动态查询构建。要插入、更新和删除,您可以使用Zend_Db_适配器或Zend_Db_表和Zend_Db_表行中的代理方法或通用Zend_Db_语句


然而,尽管如此,我认为扩展Zend_Db_Select并根据您的需要对其进行调整并没有什么错,就像任何其他组件一样,这些组件一开始并不能满足您的需要

如果您确信您不会让它在将来发展得太多,那么这个类就可以了。我假设您的方法是受益于Zend_Db_Select类中的自动引用。然而,依我拙见,如果您需要修改或扩展它,它存在一些设计缺陷,可能会导致扩展性问题:

它接收一些数据,这些数据在实体对象之后被丢弃,以使用from子句。 它直接操作select查询的SQL输出,这可能是一种危险的依赖。如果格式发生变化,并且如果您需要在where子句中包含更多元素,那么您的代码可能会变得非常混乱,无法适应这些变化。 我的方法是直接在代码中使用where子句,并在必要时引用它们。在我看来,它并不是特别不干净。如下所示:

$db->delete('tablename', 'id = ' . $db->quote('1'));
private function myDelete($tableName, array $fields)
{
    $whereClauses = array();
    foreach ($fields as $fieldName => $fieldValue) {
       $whereClauses[] = $fieldName . ' = ' . $db->quote($fieldValue);
    }
    $this->db->delete($tableName, implode(' AND ', $whereClauses));
}

$this->myDelete('tablename', array('id' => '1', 'name' => 'john'));
最终,您甚至可以将其抽象为一个方法或类,以避免将$db->quote调用分散到各个地方,类似这样:

private function myDelete($tableName, $fieldName, $fieldValue)
{
    $this->db->delete($tableName, $fieldName . ' = ' . $db->quote($fieldValue));
}
编辑:在where部分中包含多个子句将使其更加复杂,并且您希望的灵活性将取决于您的特定应用程序。例如,几个ANDed条款的可能解决方案如下:

$db->delete('tablename', 'id = ' . $db->quote('1'));
private function myDelete($tableName, array $fields)
{
    $whereClauses = array();
    foreach ($fields as $fieldName => $fieldValue) {
       $whereClauses[] = $fieldName . ' = ' . $db->quote($fieldValue);
    }
    $this->db->delete($tableName, implode(' AND ', $whereClauses));
}

$this->myDelete('tablename', array('id' => '1', 'name' => 'john'));

希望这能有所帮助,

谢谢你的回复,你的报价是对的。我正在尝试自动引用所有内容,这样程序员就不必费心引用所有内容,即使他忘记了,也很安全。但是,myDelete函数如何处理where中的多个值?比如:删除id=3或address='test'和language!='根据WHERE子句的复杂程度,您需要或多或少地修改代码。我将答案编辑为仅使用AND和字段相等,只是为了展示一个简单的示例。我以前尝试过类似的方法,但发现自己陷入了类似数组键的问题。像这样的情况:数组'id'=>3,'id'=>4这样使用它来启用大于可能性的数组'id=?'=>3,'id=?'=>4正如我所说的,我认为您需要缩小问题的范围,只包括在where上可能得到的值,否则可能会使解决方案过于复杂。如果需要处理标识符采用多个可能值的情况,可以这样做:array'id'=>array'3',4'。但同样,复杂性将取决于应用程序中可能出现的where情况的范围。