ВыходВход

Меню сайта

Категории статей
Теория [1]
Древовидные структуры данных. Методология, описание
Использование в SQL DB [0]
Решения используемые в SQL DB
Использование в Perl [7]
Применение технологии Nested Sets в Perl программировании
Использование в PHP [2]
Применение технологии Nested Sets в PHP программировании

Меню пользователя

Поиск по статьям

Друзья сайта

Модуль Perl - 2. Перемещение (часть вторая)
» Каталог статей » Использование в Perl
Модуль Perl - 2. Перемещение (часть вторая)

Модуль Perl - 2. Перемещение (часть вторая)

4.3. Изменение уровня узла

Перемещение узла на уровень вверх - не особо сложная процедура: нужно просто определить родительский узел, и установить перемещаемый узел рядом, на одном уровне. Перемещение на уровень вниз по дереву - так же несложно, для того, что бы это сделать нужно определить, соседний узел (я использую вышестоящий по списку), и переместить узел в его подчинение. Это, правда, совсем не значит, что нам нужно будет использовать два предыдущих метода. Наша задача - определить, в первом случае - правый ключ родителя и его уровень, во втором - тот же правый ключ соседнего узла и его уровень (правда, при этом, мы будем использовать значения на единицу меньшие), итак:

Для того, что бы переместить узел на уровень вверх - вниз нужны следующие данные:

  • параметры перемещаемого узла;
  • параметр перемещения узла - уровень вверх или уровень вниз.
  • порядок перемещения - в начало или конец списка

И произвести следующие действия:

  • определить параметры перемещаемого узла (если они еще не определены);
  • определить параметры родительского или соседнего узла, в зависимости от параметра перемещения;
  • передать полученные данные процедуре _move_unit
sub set_unit_level {
# Получаем данные: объект, перемещаемый узел, место перемещения, порядок перемещения 
    my ($self, %common)= @_;
# перемещаемый узел
    my $unit = $common{'unit'} || undef;
# место перемещения
    my $move = $common{'move'} || undef;
    return 0 unless $move;
# порядок перемещения (top - в начало, иначе - в конец списка) 
    my $order = $common{'order'} || undef;
# объявляем переменную, которую будем передавать процедуре перемещения
    my $data;
# определяем данные перемещаемого узла
    if ($unit) {$self = &select_unit($self, $unit)}
    elsif (!$self->{'unit'}->{'id'}) {croak("NestedSets failed: Your must first select unit, for moving it!!!")}
# если на уровень вверх
    if ($move eq 'up') {
# определяем данные места перемещения - узла, рядом с которым 
# будет располагаться перемещаемый узел
        my $sql = 'SELECT '.
                      $self->{'right'}.' AS rk, '.
                      $self->{'level'}.' AS lv FROM '. $self->{'table'}.
                  ' WHERE '.
                      $self->{'left'}.' < '.$self->{'unit'}->{'left'}.' AND '.
                      $self->{'right'}.' > '.$self->{'unit'}->{'right'}.' AND '.
                      $self->{'level'}.' = '.$self->{'unit'}->{'level'}.' - 1 '.
                      ($self->{'type'} eq 'M' ? 
                       ' AND '.$self->{'multi'}.'= \''.$self->{'unit'}->{'multi'}.'\'' : ''); 
        my $sth = $self -> {'DBI'} -> prepare($sql); $sth -> execute();
        my $row = $sth -> fetchrow_hashref();
        $sth -> finish();
        if ($row) {
            $data->{'near'} = $$row{'rk'}; 
            $data->{'level_new'} = $$row{'lv'}
        } else {return 0} 
# если на уровень вниз
    } elsif ($move eq 'down') {
# определяем данные места перемещения - узла, новый родитель 
        my $sql = 'SELECT '.
                      $self->{'right'}.' AS rk, '.
                      $self->{'left'}.' AS lk, '.
                      $self->{'level'}.' AS lv FROM '.$self->{'table'}.
                  ' WHERE '.
                      $self->{'right'}.' = '.$self->{'unit'}->{'left'}.' - 1'.
                      ($self->{'type'} eq 'M' ? 
                       ' AND '.$self->{'multi'}.'= \''.$self->{'unit'}->{'multi'}.'\'' : '');
        my $sth = $self -> {'DBI'} -> prepare($sql); $sth -> execute();
        my $row = $sth -> fetchrow_hashref();
        $sth -> finish();
        if ($row && (($order && $order eq 'top') || $self->{'order'} eq 'T')) {
            $data->{'near'} = $$row{'lk'};
            $data->{'level_new'} = $$row{'lv'} + 1 
        } elsif ($row) {
            $data->{'near'} = $$row{'rk'} - 1; 
            $data->{'level_new'} = $$row{'lv'} + 1
        } else {return 0}
    } else {return 0} 
# перебрасываем из объекта данные о перемещаемом узле
    $data->{'left'} = $self->{'unit'}->{'left'};
    $data->{'right'} = $self->{'unit'}->{'right'};
    $data->{'level'} = $self->{'unit'}->{'level'};
    $data->{'multi'} = $self->{'unit'}->{'multi'} || undef;
    $self->{'unit'} = undef; 
# перемещаем узел 
    &_move_unit($self, $data);
    return 1 
}

Вызов данного метода производится так:

...
    my $unit = ... # Определяем идентификатор узла 
... 
use MyModule::NestedSets;
my $nested = new MyModule::NestedSets {table=>'catalog_category', type=>'M', DBI=>$dbh};
$nested->set_unit_level(unit=>$unit, move=>'up', order=>'top');
... 

или так:

...
    my $unit = ... # Определяем идентификатор узла 
... 
use MyModule::NestedSets;
my $nested = new MyModule::NestedSets {table=>'catalog_category', type=>'M', DBI=>$dbh};
$nested->select_unit($unit);
$nested->set_unit_level(move=>'down', order=>'top');
... 

4.4. Изменение порядка узла

Не смотря на то, что у нас есть метод перемещения узла в точку, рядом с другим. Часто требуется простое перемещение узла по порядку вверх или вниз. Используя вышесказаный метод, нам будет нужно определить этот соседний узел, что приводит к лишним операциям, поэтому целесообразно описать отдельную процедуру для управления порядком, в пределах одного подчинения. Данные, которые нам понадобятся:

  • параметры перемещаемого узла;
  • параметры перемещения (вверх - вниз)

Действия, точно такие же как и в предыдущих методах.

sub set_unit_order {
# Получаем данные: объект, перемещаемый узел, порядок перемещения 
    my ($self, %common)= @_;
# перемещаемый узел
    my $unit = $common{'unit'} || undef;
# место перемещения
    my $move = $common{'move'} || undef;
    return 0 unless $move;
# объявляем переменную, которую будем передавать процедуре перемещения
    my $data;
# определяем данные перемещаемого узла
    if ($unit) {$self = &select_unit($self, $unit)}
    elsif (!$self->{'unit'}->{'id'}) {croak("NestedSets failed: Your must first select unit, for moving it!!!")}
# определяем данные места перемещения - узла, за которым 
# будет располагаться перемещаемый узел
    if ($move eq 'up') {
        my $sql = 'SELECT '.
                    $self->{'left'}.' AS lk '.
                  ' FROM '.$self->{'table'}.
                  ' WHERE '.
                    $self->{'right'}.' = '.$self->{'unit'}->{'left'}.' - 1 '.
                    ($self->{'type'} eq 'M' ? 
                     ' AND '.$self->{'multi'}.'= \''.$self->{'unit'}->{'multi'}.'\'' : ''); 
        my $sth = $self -> {'DBI'} -> prepare($sql); $sth -> execute();
        my $row = $sth -> fetchrow_hashref();
        $sth -> finish();
        if ($row) {$data->{'near'} = $$row{'lk'} - 1} else {return 0} 
    } elsif ($move eq 'down') {
        my $sql = 'SELECT '.
                    $self->{'right'}.' AS rk '.
                  ' FROM '.$self->{'table'}.
                  ' WHERE '.
                    $self->{'left'}.' = '.$self->{'unit'}->{'right'}.' + 1'.
                    ($self->{'type'} eq 'M' ?
                     ' AND '.$self->{'multi'}.'= \''.$self->{'unit'}->{'multi'}.'\'' : '');
        my $sth = $self->{'DBI'}->prepare($sql); $sth->execute();
        my $row = $sth->fetchrow_hashref();
        $sth -> finish();
        if ($row) {$data->{'near'} = $$row{'rk'}} else {return 0}
    }
# перебрасываем из объекта данные о перемещаемом узле
    $data->{'left'} = $self->{'unit'}->{'left'};
    $data->{'right'} = $self->{'unit'}->{'right'};
    $data->{'level'} = $self->{'unit'}->{'level'};
# Так как работаем в перделах одного подчинения, то уровень не меняется 
    $data->{'level_new'} = $self->{'unit'}->{'level'};
    $data->{'multi'} = $self->{'unit'}->{'multi'} || undef;
    $self->{'unit'} = undef; 
# перемещаем узел 
    &_move_unit($self, $data);
    return 1 
}

Вызов данного метода, как всегда:

...
    my $unit = ... # Определяем идентификатор узла 
... 
use MyModule::NestedSets;
my $nested = new MyModule::NestedSets {table=>'catalog_category', type=>'M', DBI=>$dbh};
$nested->set_unit_order(unit=>$unit, move=>'up');
... 

или так:

...
    my $unit = ... # Определяем идентификатор узла 
... 
use MyModule::NestedSets;
my $nested = new MyModule::NestedSets {table=>'catalog_category', type=>'M', DBI=>$dbh};
$nested->select_unit($unit);
$nested->set_unit_order(move=>'down');
... 

5. Вернемся к созданию объекта

В процессе, написания модуля, мы правили несколько раз процедуру new, теперь стоит посмотреть, что из нее получилось:

sub new {
# Получаем ссылку на переменную и входные параметры 
    my ($self, $common) = @_;
# Описываем переменную, как ссылку на хеш хешей 
    $self = {
             id    => 'id',        # имя поля  таблицы - идентификатор
             left  => 'left_key',  # имя поля  таблицы  - левый ключ
             right => 'right_key', # имя поля  таблицы - правый ключ 
             level => 'level',     # имя поля таблицы - уровень 
             multi => 'class',     # имя поля таблицы - идентификатор дерева
             table => undef,       # имя таблицы
             DBI   => undef,       # подключение к базе данных 
             type  => 'N',         # мультидерево или нет 
             order => 'B',         # порядок вставки, перемещения
             unit  => {            # текущий (выбранный) элемент
                       id    => undef,   # идентификатор элемента
                       left  => undef,   # левый ключ элемента
                       right => undef,   # правый ключ элемента
                       level => undef,   # уровень элемента
                       multi => undef,   # идентификатор дерева элемента
                      },
            };
# Обработка входных параметров 
    $self->{'type'} = $$common{'type'} && $$common{'type'} eq 'multi' ? 'M' : 'N';
    $self->{'order'} = $$common{'order'} && $$common{'order'} eq 'top' ? 'T' : 'B';
    $self->{'left'} = $$common{'left'} if $$common{'left'};
    $self->{'right'} = $$common{'right'} if $$common{'right'};
    $self->{'level'} = $$common{'level'} if $$common{'level'};
    $self->{'multi'} = $$common{'multi'} if $$common{'multi'};
    $self->{'table'} = $$common{'table'} if $$common{'table'};
    $self->{'DBI'} = $$common{'DBI'} if $$common{'DBI'};
# "благословление" объекта на работу ;-) 
    bless $self; 
    return $self;
}
Категория: Использование в Perl | Добавил: phoinix (2005-10-31) | Автор: Сергей Томулевич (aka Phoinix)
Просмотров: 2038 | Рейтинг: 0.0 |

Комментарии

 

Бесплатный конструктор сайтов - uCoz