Лучший способ получить данные HABTM, HasMany ... и т. Д., Чем -1 рекурсивное ручное соединение в CakePHP? - PullRequest
1 голос
/ 02 июля 2011

У меня есть база событий. Я создал модель-функцию для извлечения событий на основе города, типа, подтипа, даты начала и окончания.

Это работает (в основном), но, черт возьми, это новая ценность кода. Есть лучший способ сделать это? (Кода много, но не сложно понять, что я делаю):

Некоторые из моих ассоциаций:

Event belongsTo Restaurant
Event belongsTo Venue
Restaurant belongsTo City
Venue belongsTo City

Event hasAndBelongsToMany EventType
Event hasAndBelongsToMany EventSubType

Event hasMany Schedule
Schedule hasMany Date

(and of course their belongsTo/hasMany counterparts are set up too)

Моя функция "getEvents" (в модели событий):

function getEvents($opts) {
    //$opts = limit, start, end, fields, types, subtypes, subsubtypes, cities

    //dates
    $qOpts['start'] = date('Y-m-d') . ' 00:00:00';
    if(isset($opts['start'])) $qOpts['start'] = $opts['start'];

    $qOpts['end'] = date('Y-m-d') . ' 23:59:59';
    if(isset($opts['end'])) $qOpts['end'] = $opts['end'];

    //limit
    if(isset($opts['limit'])) $qOpts['limit'] = $opts['limit'];

    //fields
    $qOpts['fields'] = array('Event.id', 'Event.name', 'Event.slug', 'City.name', 'Date.start');    
    if(isset($opts['fields'])) $qOpts['fields'] = $opts['fields'];

    //joins
    $qOpts['joins'] = array(
        array('table' => 'schedules',
            'alias' => 'Schedule',
            'type' => 'LEFT',
            'conditions' => array(
                'Event.id = Schedule.event_id',
            )
        ),
        array('table' => 'dates',
            'alias' => 'Date', 
            'type' => 'LEFT',
            'order' => 'Date.start ASC',
            'conditions' => array(
                'Date.schedule_id = Schedule.id',
            ),
        ),
        array('table' => 'venues',
            'alias' => 'Venue',
            'type' => 'LEFT',
            'conditions' => array(
                'Event.venue_id = Venue.id',
            )
        ),
        array('table' => 'restaurants',
            'alias' => 'Restaurant',
            'type' => 'LEFT',
            'conditions' => array(
                'Event.restaurant_id = Restaurant.id',
            )
        ),
        array('table' => 'cities',
            'alias' => 'City',
            'type' => 'LEFT',
            'conditions' => array(
                'OR' => array(
                    'Venue.city_id = City.id',
                    'Restaurant.city_id = City.id',
                ),
            )
        ),
        array('table' => 'event_types_events',
            'alias' => 'EventTypesEvent',
            'type' => 'LEFT',
            'conditions' => array(
                'EventTypesEvent.event_id = Event.id',
            )
        ),
        array('table' => 'event_sub_types_events',
            'alias' => 'EventSubTypesEvent',
            'type' => 'LEFT',
            'conditions' => array(
                'EventSubTypesEvent.event_id = Event.id',
            )
        ),
        array('table' => 'event_types',
            'alias' => 'EventType',
            'type' => 'LEFT',
            'conditions' => array(
                'EventTypesEvent.event_type_id = EventType.id',
            )
        ),
        array('table' => 'event_sub_types',
            'alias' => 'EventSubType',
            'type' => 'LEFT',
            'conditions' => array(
                'EventSubTypesEvent.event_sub_type_id = EventSubType.id',
            )
        ),
    );

    //date conditions
    $qOpts['conditions'] = array(
        "Date.start >=" => $qOpts['start'],
        "Date.start <=" => $qOpts['end'],
    );

    //cities conditions
    if(isset($opts['cities'])) {
        if(is_array($opts['cities'])) {
            $cityConditions['OR'] = array();
            foreach($opts['cities'] as $city_id) {
                array_push($cityConditions['OR'], array('City.id'=>$city_id));
            }
            array_push($qOpts['conditions'], $cityConditions);
        }
    }

    //event types conditions
    if(isset($opts['event_types'])) {
        if(is_array($opts['event_types'])) {
            $eventTypeConditions['OR'] = array();
            foreach($opts['event_types'] as $event_type_id) {
                array_push($eventTypeConditions['OR'], array('EventType.id'=>$event_type_id));
            }
            array_push($qOpts['conditions'], $eventTypeConditions);
        }
    }

    //event sub types conditions
    if(isset($opts['event_sub_types'])) {
        if(is_array($opts['event_sub_types'])) {
            $eventSubTypeConditions['OR'] = array();
            foreach($opts['event_sub_types'] as $event_sub_type_id) {
                array_push($eventSubTypeConditions['OR'], array('EventSubType.id'=>$event_sub_type_id));
            }
            array_push($qOpts['conditions'], $eventSubTypeConditions);
        }
    }

    $this->recursive = -1;
    $data = $this->find('all', $qOpts);
    return $data;
}

Бонусные баллы: У меня есть вопрос по StackOverflow (здесь) , который также спрашивает об этой функции - пытаясь выяснить, как заставить ее возвращать несколько дат вместо просто по одному на событие.

1 Ответ

2 голосов
/ 02 июля 2011

Дейв, придурок, просто настройте свои ассоциации правильно и выполните обычную (рекурсивную) find().Если вам нужен больший контроль над связанными полученными данными, используйте ContainableBehavior .

Если у вас есть условия для некоторой связанной модели, требующей объединения других таблиц в основной запрос,другая тема, и есть много способов сделать это (поиск SO или задать конкретный вопрос).Для этого могут быть уместны ручные соединения.Вам не нужно вручную объединять таблицы только для получения связанных данных.

...