Использование компонентов CakePHP в компонентах через App :: import - PullRequest
1 голос
/ 14 июня 2011

Я использую CakePHP для создания приложения, которое, помимо прочего, генерирует десятки графиков.Чтобы упростить загрузку этих графиков, я следую заводскому шаблону с использованием компонентов.Существует один ChartComponent, который отвечает за загрузку компонентов для генерации отдельных графиков, и эти отдельные графики, в свою очередь, могут использовать компоненты для подготовки своих данных.

Образец GraphComponent:

class ChartComponent extends Object {
    var $name = 'Chart';

    function getChart($category, $chart, $node) {
        // Build the name we expect to find the component as.
        $component_name = Inflector::camelize("{$category}_{$chart}_graph");
        $component_class = "{$component_name}Component";

        // Import the component, making sure it actually exists.
        if (! App::import('Component', $component_name)) {
            return false;
        }

        $chart = new $component_class();
        return $chart->getData($node);
    }
}

Образецкомпонент для отдельного графика:

class StoreRevenueGraphComponent extends Object {
    var $name = 'StoreRevenueGraph';
    var $components = array('Calculations');

    function getData($node) {
        var_dump(isset($this->Calculations));
    }
}

Однако, когда я запускаю этот код, компонент Calcluations не загружается успешно, и isset ($ this-> Calculations) возвращает false.

Я предполагаю,это потому, что я где-то пропускаю какой-то код инициализации.Кто-нибудь знает, какие еще шаги я должен предпринять, чтобы использовать компоненты внутри другого компонента через App :: import, или это то, что я пытаюсь сделать невозможным внутри торта?

Решение

Как отметил Эндрю, при создании экземпляров компонентов вручную массив var $ components никогда не обрабатывается, в результате чего они никогда не загружаются.Решение состоит в том, чтобы вручную сделать это так:

function startup(&$controller) {
    foreach ($this->components as $component_name) {
        App::import('Component', $component_name);
        $component_class = "{$component_name}Component";
        $this->$component_name = new $component_class();
        $this->$component_name->startup($this);
    }
}

Ответы [ 5 ]

1 голос
/ 22 июня 2013

В Cake 2.3 решение, приведенное в оригинальном сообщении, выдает ошибку предупреждения, хотя оно работает правильно и не возвращает false:

Предупреждение (4096): аргумент 1, переданный в Component :: startup (), должен быть Экземпляр Controller, данный экземпляр MessagesComponent, вызванный в ... (удалено) ... / MessagesComponent.php в строке 26 и определено [CORE / cake-lib-2.3.1 / Controller / Component.php, строка 120]

Оскорбительная строка:

$this->$component_name->startup($this);

Я обновил его до

$this->$component_name->startup($controller);

, и это устраняет ошибку и функционирует должным образом.

Полная рабочая версия для 2.3:

   function startup(&$controller) {
        foreach ($this->components as $component_name) 
        {
            App::import('Component', $component_name);
            $component_class = "{$component_name}Component";
            $this->$component_name = new $component_class();
            $this->$component_name->startup($controller);
        }
    }

Добавление:

Обновление ОС до Ubuntu 14.04 с более новой версией PHP (5.5.9) привело к появлению нового предупреждающего сообщения (все еще использующего CakePHP 2.3.6, более поздние версии Cake могут не иметь этой проблемы):

Строгое (2048): объявление MessagesComponent :: startup () должно быть совместимо с Component :: startup (Controller $ controller) [APP / Controller / Component / MessagesComponent.php, строка 0]

Чтобы устранить это, объявление для запуска нужно было изменить с:

function startup(&$controller) {

до:

function startup(Controller $controller) {
1 голос
/ 28 декабря 2011

Почти там ... исправлен метод запуска ():

   function startup(&$controller) {
        foreach ($this->components as $component_name) 
        {
            App::import('Component', $component_name);
            $component_class = "{$component_name}Component";
            $this->$component_name = new $component_class();
            $this->$component_name->startup($this);
        }
    }
1 голос
/ 14 июня 2011

Свойство $components можно использовать только в контроллерах. Если вы хотите, чтобы один компонент загружал несколько других компонентов, вы можете переопределить метод startup в своем компоненте, создать компонент и назначить его вручную. в собственность ->Calculations.

Как это:

function startup( $controller ) {
  $this->Calculations = new Foo();
  $this->Calculations->startup($component);
}

Однако это немного странно. Что наиболее вероятно в большинстве приложений, так это то, что вы хотите загрузить его в сам контроллер. Таким образом, код становится:

$component->Calculations = new Foo();
$component->Calculations->startup($component);

Если компонент никогда не используется непосредственно контроллером, может быть лучше поместить классы в каталог vendors и использовать их в качестве внешних библиотек.

[править]

См. Комментарии после этого ответа.

0 голосов
/ 11 февраля 2014

Вы можете использовать как ниже:)

class YourComponent extends Component {
  public function initialize(Controller $controller)
   {
     $this->controller = $controller;
  if (!isset($this->controller->presetVars)) {
        $this->controller->presetVars = true;
    }

    $model = $this->controller->modelClass;
    if (!empty($settings['model'])) {
        $model = $settings['model'];
    }

    if ($this->controller->presetVars === true) {
        // auto-set the presetVars based on search definitions in model
        $this->controller->presetVars = array();
        $filterArgs = array();
        if (!empty($this->controller->$model->filterArgs)) {
            $filterArgs = $this->controller->$model->filterArgs;
        }

        foreach ($filterArgs as $key => $arg) {
            if ($args = $this->_parseFromModel($arg, $key)) {
                $this->controller->presetVars[] = $args;
            }
        }
    }
    foreach ($this->controller->presetVars as $key => $field) {
        if ($field === true) {
            if (isset($this->controller->$model->filterArgs[$key])) {
                $field = $this->_parseFromModel($this->controller->$model->filterArgs[$key], $key);
            } else {
                $field = array('type' => 'value');
            }
        }
        if (!isset($field['field'])) {
            $field['field'] = $key;
        }
        $this->controller->presetVars[$key] = $field;

   }

  /* now you can use Component existing in your Component :) */
  public function sayHello(){
     $this->controller->Session->setFlash(__('Hello you'));
  }

}
0 голосов
/ 21 декабря 2012

Что касается поваренной книги , вы можете загружать другие компоненты так же, как контроллеры.Вы можете объявить это внутри $ компоненты var.

// app/Controller/Component/CustomComponent.php
App::uses('Component', 'Controller');
class CustomComponent extends Component {
    // the other component your component uses
    public $components = array('Existing');

    public function initialize(Controller $controller) {
        $this->Existing->foo();
    }

    public function bar() {
        // ...
   }
}

// app/Controller/Component/ExistingComponent.php
App::uses('Component', 'Controller');
class ExistingComponent extends Component {

    public function foo() {
        // ...
    }
}
...