自定义is_unique_logical_key - 验证还是回调?

时间:2012-11-24 01:31:18

标签: php codeigniter-2 grocery-crud

我可以针对以下问题提出设计建议:

我正在使用Codeigniter / Grocery_CRUD。

我的系统是多租户 - 不同的自治站点 - 在同一个客户端内。我有很多具有唯一逻辑键的表实例。一个这样的表结构是:

equip_items
id(pk)
equip_type_id(fk to equip_types)
site_id(fk to sites)
名称

其中(equip_type_id,site_id,name)一起是我的数据库中的唯一键。

问题在于,当使用grocery_CRUD表单添加或编辑破坏此数据库规则的记录时 - 添加或编辑失败(由于数据库中的约束),但我没有得到任何反馈。

我需要对is_unique form_validation规则进行修改,通过该规则我可以​​指定必须唯一的字段* s *。

问题:
如何指定规则? set_rules()用于给定字段,我有多个规则将应用于的字段。这是否意味着我应该放弃Form_validation模式?或者我是否遵循“匹配”规则模式并以某种方式指向其他字段?

也许一个回调函数会更好,但这意味着在每个模型中编写一个自定义函数,我在这个问题上最后计算这是9个表。在一个地方执行此操作似乎要好得多(扩展form_validation)。

我是否遗漏了已经解决了这个问题的codeigniter或grocery_CRUD中的内容?

您可能会有任何建议/意见。

修改 实际上看起来Johnny提供的解决方案并没有达到标记 - 它强制unique_fields()中的每个字段独立地唯一 - 与每个字段上的设置is_unique()相同。我的问题是,在我的场景中,这些字段是复合唯一键(但不是主键)。我不知道它是否重要但是对原始问题陈述更进一步:1)site_id是一个'隐藏'field_type - 我不希望我的用户担心他们在不同的网站上所以我正在处理后面的site_id场景。 2)处理equip_status_id属性(不是唯一键的一部分)。 3)我对所有这些外键属性都有set_relations(),而grocery_CRUD对我有好处。

编辑2 我已经使用回调解决了这个问题。

2 个答案:

答案 0 :(得分:11)

更新:此代码现在是杂货CRUD版本> = 1.4的一部分,您不再需要使用扩展程序了。有关更多信息,请参阅unique_fields

的文档

我会尽力解释它:

1。首先,对于那些杂货店CRUD低于或等于1.3.3的人,必须使用这个小改动:https://github.com/scoumbourdis/grocery-crud/commit/96ddc991a6ae500ba62303a321be42d75fb82cb2

2. 二,在应用程序/库中创建名为grocery_crud_extended.php的文件

3. 将以下代码复制到您的文件application / libraries / grocery_crud_extended.php

<?php 
class grocery_CRUD_extended extends grocery_CRUD
{
    protected $_unique_fields = array();

    public function unique_fields()
    {
        $args = func_get_args();

        if(isset($args[0]) && is_array($args[0]))
        {
            $args = $args[0];
        }

        $this->_unique_fields = $args;

        return $this;
    }

    protected function db_insert_validation()
    {
        $validation_result = (object)array('success'=>false);

        $field_types = $this->get_field_types();
        $unique_fields = $this->_unique_fields;
        $add_fields = $this->get_add_fields();

        if(!empty($unique_fields))
        {
            $form_validation = $this->form_validation();

            foreach($add_fields as $add_field)
            {
                $field_name = $add_field->field_name;
                if(in_array( $field_name, $unique_fields) )
                {
                    $form_validation->set_rules( $field_name, 
                            $field_types[$field_name]->display_as, 
                            'is_unique['.$this->basic_db_table.'.'.$field_name.']');
                }
            }

            if(!$form_validation->run())
            {
                $validation_result->error_message = $form_validation->error_string();
                $validation_result->error_fields = $form_validation->_error_array;

                return $validation_result;
            }
        }
        return parent::db_insert_validation();
    }

    protected function db_update_validation()
    {
        $validation_result = (object)array('success'=>false);

        $field_types = $this->get_field_types();
        $unique_fields = $this->_unique_fields;
        $add_fields = $this->get_add_fields();

        if(!empty($unique_fields))
        {
            $form_validation = $this->form_validation();

            $form_validation_check = false;

            foreach($add_fields as $add_field)
            {
                $field_name = $add_field->field_name;
                if(in_array( $field_name, $unique_fields) )
                {
                    $state_info = $this->getStateInfo();
                    $primary_key = $this->get_primary_key();
                    $field_name_value = $_POST[$field_name];

                    $ci = &get_instance();
                    $previous_field_name_value = 
                        $ci->db->where($primary_key,$state_info->primary_key)
                            ->get($this->basic_db_table)->row()->$field_name;

                    if(!empty($previous_field_name_value) && $previous_field_name_value != $field_name_value) {
                        $form_validation->set_rules( $field_name, 
                                $field_types[$field_name]->display_as, 
                                'is_unique['.$this->basic_db_table.'.'.$field_name.']');

                        $form_validation_check = true;
                    }
                }
            }

            if($form_validation_check && !$form_validation->run())
            {
                $validation_result->error_message = $form_validation->error_string();
                $validation_result->error_fields = $form_validation->_error_array;

                return $validation_result;
            }
        }
        return parent::db_update_validation();
    }   

}

4. 现在你只需加载那样的grocery_CRUD_extended:

    $this->load->library('grocery_CRUD');
    $this->load->library('grocery_CRUD_extended');

然后使用:

$crud = new grocery_CRUD_extended();

而不是:

$crud = new grocery_CRUD();

5. 现在你可以简单地使用像这样工作的unique_fields:

$crud->unique_fields('field_name1','field_name2','field_name3');

在你的情况下:

$crud->unique_fields('equip_type_id','site_id');

很简单吧?

这是检查字段是否唯一,而不实际更改杂货CRUD的核心。你可以简单地使用grocery_CRUD_extended而不是grocery_CRUD并正常更新杂货CRUD库。由于我是该库的作者,我将尝试将其包含在杂货CRUD版本1.4中,因此您将来不必使用grocery_CRUD_extended。

答案 1 :(得分:3)

我使用回调完成了这个:

$crud->set_rules('name','Name','callback_unique_equip_item_check['.$this->uri->segment(4).']');     

function unique_equip_item_check($str, $edited_id)
{
    $var = $this->Equip_Item_model->is_unique_except(
            $edited_id,
            $this->input->post('site_id'),
            $this->input->post('equip_type_id'),
            $this->input->post('name'));

    if ($var == FALSE) {
        $s = 'You already have an equipment item of this type with this name.';
        $this->form_validation->set_message('unique_equip_item_check', $s);
        return FALSE;
        }
    return TRUE;
}