Заполнить таблицу вложенным набором Doctrine 1.2 - PullRequest
0 голосов
/ 22 июля 2011

Я пытаюсь заполнить набор таблиц несколькими корневыми местоположениями, вложенными в три уровня: Регион, Провинция и Город.

данные, чтобы сохранить их из файла Excel, который я читаю.

я пишу этот скрипт:

function importLocations()
{

    $objPHPExcel = PHPExcel_IOFactory::load("./data/elenco_comuni_italiani_30_giugno_2011.xls");

    $locationTable = LocationTable::getInstance();
    /* @var $tree Doctrine_Tree_NestedSet */
    $tree = $locationTable->getTree();

    $startRow = 2;
    $indexRegion = 0;
    $indexProvince = 2;
    $indexCity = 1;

    $objPHPExcel->setActiveSheetIndex($indexRegion);
    $objWorksheetRegion = $objPHPExcel->getActiveSheet();
    $highestRowRegion = $objWorksheetRegion->getHighestRow();
    $highestColumnRegion = $objWorksheetRegion->getHighestColumn();
    $highestColumnIndex = PHPExcel_Cell::columnIndexFromString($highestColumnRegion);
    for ($rowRegion = $startRow; $rowRegion <= $highestRowRegion; ++$rowRegion) {
        $region_name = $objWorksheetRegion->getCellByColumnAndRow(0, $rowRegion)->getValue();
        $region_id = $objWorksheetRegion->getCellByColumnAndRow(1, $rowRegion)->getValue();
        // create a new root in the tree
        $tree->createRoot($nodeRegion = $locationTable->createNode($region_name));
        echo "\n\Process to Region: $region_name \n";
        //province
        $objPHPExcel->setActiveSheetIndex($indexProvince);
        $objWorksheetProvince = $objPHPExcel->getActiveSheet();
        $highestRowProvince = $objWorksheetProvince->getHighestRow();
        $highestColumnProvince = $objWorksheetProvince->getHighestColumn();
        $highestColumnIndex = PHPExcel_Cell::columnIndexFromString($highestColumnProvince);
        for ($rowProvince = $startRow; $rowProvince <= $highestRowProvince; ++$rowProvince) {
            $province_name = $objWorksheetProvince->getCellByColumnAndRow(0, $rowProvince)->getValue();
            $province_code = $objWorksheetProvince->getCellByColumnAndRow(1, $rowProvince)->getValue();
            $province_region_id = $objWorksheetProvince->getCellByColumnAndRow(2, $rowProvince)->getValue();
            $province_id = $objWorksheetProvince->getCellByColumnAndRow(3, $rowProvince)->getValue();
            if ($province_region_id == $region_id) {
                //create province node and append it to the region
                $nodeProvince = $locationTable->createNode($province_name, $province_code);
                $locationTable->appendNode($nodeProvince, $nodeRegion);
                echo "Process to Province: $province_name \n";
                //city
                $objPHPExcel->setActiveSheetIndex($indexCity);
                $objWorksheetCity = $objPHPExcel->getActiveSheet();
                $highestRowCity = $objWorksheetCity->getHighestRow();
                $highestColumnCity = $objWorksheetCity->getHighestColumn();
                $highestColumnIndex = PHPExcel_Cell::columnIndexFromString($highestColumnCity);
                for ($rowCity = $startRow; $rowCity <= $highestRowCity; ++$rowCity) {
                    $city_name = $objWorksheetCity->getCellByColumnAndRow(0, $rowCity)->getValue();
                    $city_province_id = $objWorksheetCity->getCellByColumnAndRow(1, $rowCity)->getValue();
                    $city_region_id = $objWorksheetCity->getCellByColumnAndRow(2, $rowCity)->getValue();
                    if ($city_region_id == $province_region_id && $city_province_id == $province_id) {
                        //create province node and append it to the region
                        $nodeCity = $locationTable->createNode($city_name);
                        $locationTable->appendNode($nodeCity, $nodeProvince);
                        echo "Process to City: $city_name \n";
                    }
                }
            }
        }
    }
    echo "Locations Salvate con Successo! \n\n\n";

}

и мой LocationTable:

/**
 * LocationTable
 *
 * This class has been auto-generated by the Doctrine ORM Framework
 */
class LocationTable extends Doctrine_Table
{

    const LEVEL_REGION = '0';
    const LEVEL_PROVINCE = '1';
    const LEVEL_CITY = '2';

    /**
     * Returns an instance of this class.
     *
     * @return object LocationTable
     */
    public static function getInstance()
    {
        return Doctrine_Core::getTable('Location');
    }

    /**
     * Developer MUST CALL $parent->refresh() before insert a new node, otherwise
     * following insertions are wrong
     *
     * @param Location $son
     * @param Location $parent
     * @link http://trac.doctrine-project.org/ticket/928
     */
    public function appendNode(Location $son, Location $parent)
    {
        // internally calls save both on parent and son
        $son->getNode()->insertAsLastChildOf($parent);
        // load new parent lft and rgt values
        $parent->refresh();
    }

    /**
     * Build a tree node, save it and return it
     *
     * @param string $label
     * @param string $code
     *
     * @return Location
     */
    public function createNode($label, $code = null)
    {
        $node = $this->create(array('name' => $label, 'code' => $code));
        $node->save();
        return $node;
    }
}

моя схема доктрины:

Location:
  tableName: locations
  actAs:
    NestedSet:
      hasManyRoots: true
      rootColumnName: root_id
  columns:
    id:
      type: integer(4)
      primary: true
      autoincrement: true
    name:
      type: string(255)
      notnull: true
    code:
      type: string(2)

проблема в том, что когда я проверяю заданный узел, мы проверяем провинцию, если я выполняю запрос вроде:

SELECT * FROM locations WHERE lft >= x AND rgt <= y

Я не могу найти город, который ожидаю найти, но нахожу гораздо больше.

сценарий, который читает файл Excel, он отлично работает. Я распечатал и прочитал весь вывод и исправил. Я думаю, что что-то не так в сохраненных значениях lft и rgt. Вы знаете, что нашли в документации несколько ошибок, которые не относятся к prensa?

1 Ответ

0 голосов
/ 26 августа 2011

В вашем определении установлено hasManyRoots. Это означает, что ваша таблица вложенных множеств содержит несколько деревьев. в каждом дереве lft и rgt строятся независимо от других деревьев, поэтому запрос с помощью SELECT * FROM locations WHERE lft >= x AND rgt <= y извлекает узлы из нескольких деревьев.

У вас есть два способа исправить это: быстрый и правильный.

Самый быстрый:

Каждая запись имеет столбец root_id (установлен в атрибуте rootColumnName, это также значение по умолчанию). Этот столбец содержит id корневого узла дерева. Итак, если вам нужно знать root_id желаемого узла и использовать его как

SELECT * FROM locations WHERE lft >= x AND rgt <= y and root_id = rid

Правильный:

Не запрашивать БД напрямую. Извлеките желаемую запись из БД как объект (например, с DQL) и затем просмотрите ее, используя getChildren или getDescendants:

// Get the node into $provincevar
$all_cities_in_province = $province->getDescendants();

См. Документация NestedSet для более подробного объяснения.

И небольшое замечание: это может быть совпадением, отсутствием кэширования или чем-то еще, но похоже, что Doctrine постоянно сбрасывает изменения, сделанные NestedSet функциями манипулирования узлами (например, createRoot, delete, insertAsLastChildOf так далее.). Но это мое наблюдение на одной машине со средой разработки.

...