自定义组件不会返回值

时间:2013-04-04 18:26:14

标签: cakephp cakephp-2.0 custom-component

好的,这就是情况。在我的beforeSave函数中,我想操作一些$this->request->data条目。

这是我的组成部分:

<?php
App::uses('Component', 'Controller');
class GetStationComponent extends Component {
    public function getStationId ($station) { 
        $stationInstance = ClassRegistry::init('Station');

        $conditions = array('OR' => array(
            array('Station.code LIKE' => $station),
            array('Station.naam LIKE' => $station),
            array('Station.naam_overig LIKE' => $station)
            ));

        $result = $stationInstance->find('list', array('conditions'=>$conditions));

        $value = array_values($result);
        $value = $value[0];

        return $value;
    }
}
?>

这是我在Controller中的beforeSave函数:

public function beforeSave($options = array()) {
        if (!empty($this->request->data['Experience']['vertrekstation']) && !empty($this->request->data['Experience']['aankomststation'])) {
            $this->request->data['Experience']['vertrekstation'] = $this->GetStation->getStationId($this->request->data['Experience']['vertrekstation']);
            $this->request->data['Experience']['aankomststation'] = $this->GetStation->getStationId($this->request->data['Experience']['aankomststation']);
        }
        return true;
    }

它应该返回站名的ID。但是在数据库中,名称本身被存储(由用户填写)而不是ID。我需要在我的组件中更改(我猜...)以返回正确的值?

(PS组件中的查询本身返回一个ID,因为起初我将'beforeSave'直接放入我保存数据的函数中,但是我的验证错误表明它不是正确的值。哪个是正确的......)

3 个答案:

答案 0 :(得分:1)

补充其他答案;要获得单个字段的值,请使用Model::field()

return $stationInstance->field('id', $conditions);

最好在此语句中添加排序顺序,以确保始终以相同的顺序返回结果:

return $stationInstance->field('id', $conditions, 'code ASC');

由于您只对模型执行单个查询,之后不执行任何操作,因此您甚至不需要中间$stationInstance变量。您的代码可以进一步简化为:

return ClassRegistry::init('Station')->field('id', $conditions, 'code ASC');

一些观察

  • 由于与电台名称的“模糊”匹配,第一个结果可能并非总是由用户打算,因此最好在您的电话中提供“自动完成”功能。结束并让用户选择正确的站点(例如,当用户意味着 Den Haag时阻止选择Den Haag HS
  • 如果电台与电台完全匹配,则应显示未找到电台的警告
  • 对于%查询,您未使用LIKE包围搜索字词。如果您打算搜索“name ”包含“,则应使用'%' . $station . '%'。对于“以”开头“使用$station . '%'
  • 正如@mark建议的那样; beforeSave()模型的回调,应位于此处。 也;验证发生后会触发beforeSave(),因此可能为时已晚。 beforeValidate()是此
  • 的最佳回调
  • 如果Experience模型已附加到Station模型,则无需使用组件,因为您可以直接访问Station模型。最好将搜索方法放在Station模型中;

将其全部移至右侧(*)位置

*)其他选项总是可行的,这只是可能的方法

将“搜索”方法添加到工作站模型;

应用程序/型号/ Station.php

public function getStationIdByName($name)
{
    $name = trim($name);

    if (empty($name)) {
        return null;
    }

    $name = '%' . $name . '%';

    $conditions = array(
        'OR' => array(
            array($this->alias . '.code LIKE' => $name),
            array($this->alias . '.naam LIKE' => $name),
            array($this->alias . '.naam_overig LIKE' => $name),
        )
    );

    return $this->field('id', $conditions, 'code ASC');
}

..并在体验模型中使用它

应用程序/型号/ Experience.php

public function beforeValidate(array $options = array())
{
    if (
        !empty($this->data[$this->alias]['vertrekstation'])
        && !empty($this->data[$this->alias]['aankomststation'])
    ) {
        // Directly access the Station-model from within the Experience Model
        $this->data[$this->alias]['vertrekstation'] 
            = $this->Station->getStationIdByName($this->data[$this->alias]['vertrekstation']);
        $this->data[$this->alias]['aankomststation']
            = $this->Station->getStationIdByName($this->data[$this->alias]['aankomststation']);
    }

    // Call parent-callback after setting the values
    return parent::beforeValidate($options);
}

[更新]使用约定,防止不必要的行为

在写完前一个例子之后,我注意到你当前的设置存在一些缺陷;

  1. 如果 vertrekstation aankomststation 应该保存电台的“外键”(电台 - id ),则不会根据CakePHP Model and Database Conventions
  2. 由于1)将此代码放在beforeValidate()内,当 更新 现有记录时,也会触发此代码。因为您使用 aankomststation vertrekstation 字段来保存工作站的名称(在表单内)和 id (在数据库内),模型将在更新时尝试通过 id 查找station-id。请注意表单 中,您仍然会使用 vertrekstation aankomstation 作为字段名称。这些字段名称​​ not 存在于您的数据库中,因此无法直接更新数据库中的数据,这是beforeValidate()回调用于
  3. 的位置
  4. 由于Experience模型需要与Station模型的两个关系(一次为departure station'vertrekstation'),一次用于arrival station'aankomststation')),您需要一个用于Station模型的别名。请参阅:Multiple relations to the same model
  5. 应用程序/型号/ Experience.php

    class Experience extends AppModel {
        /**
         * Station will be associated to the 'Experience' Model TWICE
         * For clarity, using an 'alias' for both associations
         *
         * The associated Models will be accessible via;
         * $this->DepartureStation
         * $this->ArrivalStation
         *
         * To stick to the CakePHP conventions, name the foreign keys
         * accordingly
         */
        public $belongsTo = array(
            'DepartureStation' => array(
                'className'  => 'Station',
                'foreignKey' => 'departure_station_id',
            ),
            'ArrivalStation' => array(
                'className'  => 'Station',
                'foreignKey' => 'arrival_station_id',
            )
        );
    
        public function beforeValidate(array $options = array())
        {
            // vertrekstation and aankomststation hold the 'names' of the
            // stations and will only be present if the form has been submitted
            if (
                !empty($this->data[$this->alias]['vertrekstation'])
                && !empty($this->data[$this->alias]['aankomststation'])
            ) {
                // Directly access the Station-model from within the Experience Model
                // using the *aliases*
                $this->data[$this->alias]['departure_station_id'] 
                    = $this->DepartureStation->getStationIdByName($this->data[$this->alias]['vertrekstation']);
                $this->data[$this->alias]['arrival_station_id']
                    = $this->ArrivalStation->getStationIdByName($this->data[$this->alias]['aankomststation']);
    
                // Invalidate the vertrekstation and aankomststation fields if lookup failed
                if (empty($this->data[$this->alias]['departure_station_id'])) {
                    // Unable to find a station. Mark the Form-field invalid
                    $this->invalidate('vertrekstation', __('A station with this name was not found'));
                }
                if (empty($this->data[$this->alias]['arrival_station_id'])) {
                    // Unable to find a station. Mark the Form-field invalid
                    $this->invalidate('aankomststation', __('A station with this name was not found'));
                }
    
            }
    
            // Call parent-callback after setting the values
            return parent::beforeValidate($options);
        }
    
    }
    

答案 1 :(得分:0)

Cake的find('list')选项返回一个类似

的数组
array( 1 => 'name1',
       3 => 'name2',
       //etc...
)

其中index是id,值是您在模型上设置的显示字段。 因此,当您执行$value = array_values($result);时,您将提取数组的值(即显示字段)。我假设你没有使用id作为displayField,所以这就是为什么它返回名字而不是id。

我不确定你为什么使用find('list')而不是find('first')或其他替代方法,但如果你不想因为某种原因修改它,应该返回的修复搜索获得的第一个ID是

reset($result);  //possibly not needed, but just in case
$value = key($result );

答案 2 :(得分:0)

首先,您必须了解Cake的工作原理 您的模型中没有$this->request。它是控制器的一部分。 在您的模型中,您传递的数据将直接在$this->data

public function beforeSave($options = array()) {
    parent::beforeSave($options); // you also forgot the parent call

    if (!empty($this->data[$this->alias]['vertrekstation']) && ...)) {
        $this->data[$this->alias]['vertrekstation'] = ...;
    }
    return true;
}

您的查找电话也看起来很糟糕。我不知道你想做什么。 但我强烈建议您使用debug()等来找出返回的内容并相应地更正您的代码。 如果你只对一个值感兴趣,你可能需要找到(第一个)。