lz 父子级

use Domain\Asset\Register\UseCase\CreateAsset;

require_once __DIR__ . '/../../../../functions/nestedset_assets.php';

$post = @file_get_contents('php://input');  //获取请求体,@的作用为屏蔽警告,可去除。
$post =  json_decode($post, true);

if (!isset($post[0]['criticality_code'])) {
    $post[0]['criticality_code'] = 0;
}
if (!isset($post[0]['function_code'])) {
    $post[0]['function_code'] = 0;
}
if (!isset($post[0]['asset_ff_1'])) {
    $post[0]['asset_ff_1'] = '';
}
// 直接进行添加,没有层级区分
if ($post[0]['asset_code'] == $post[0]['asset_primary_code']) {
    //criticality_code  换取id
    $criticality_query = $DB->prepare("
        SELECT  criticality_id
        FROM    mic_criticality
        WHERE criticality_code = :criticality_code
");
    $criticality_query->bindvalue(':criticality_code', $post[0]['criticality_code']);

    if (!$criticality_query->execute()) {
        Flight::error(new Exception(errorInfo($criticality_query)));
    }
    $items = [];
    $line = $criticality_query->fetch(PDO::FETCH_OBJ);
    $criticality_id = $line->criticality_id;

    //function_code 换取id
    $function_query = $DB->prepare("
        SELECT  function_id
        FROM    mic_function
        WHERE function_code = :function_code
");
    $function_query->bindvalue(':function_code', $post[0]['function_code']);

    if (!$function_query->execute()) {
        Flight::error(new Exception(errorInfo($function_query)));
    }
    $items = [];
    $line = $function_query->fetch(PDO::FETCH_OBJ);
    $function_id = $line->function_id;

    // 用location_code 换取id,
    $query = $DB->prepare("
        SELECT  location_id
        FROM    asset_location
        WHERE location_code = :location_code
");
    $query->bindvalue(':location_code', $post[0]['location_code']);

    if (!$query->execute()) {
        Flight::error(new Exception(errorInfo($query)));
    }
    $items = [];
    $line = $query->fetch(PDO::FETCH_OBJ);
    $location_id = $line->location_id;

    // 大类code换去大类id
    $category_query = $DB->prepare("
        SELECT  asset_category_id
        FROM    mic_asset_category
        WHERE asset_category_code = :asset_category_code
");
    $category_query->bindvalue(':asset_category_code', $post[0]['asset_category_code']);

    if (!$category_query->execute()) {
        Flight::error(new Exception(errorInfo($category_query)));
    }

    $line = $category_query->fetch(PDO::FETCH_OBJ);
    $asset_category_id = $line->asset_category_id;

    // 根据供应商code 获取供应商ID
    $pur_supplier_query = $DB->prepare("
        SELECT  supplier_id
        FROM    pur_supplier
        WHERE supplier_code = :supplier_code
");
    $pur_supplier_query->bindvalue(':supplier_code', $post[0]['supplier_code']);

    if (!$pur_supplier_query->execute()) {
        Flight::error(new Exception(errorInfo($pur_supplier_query)));
    }

    $line = $pur_supplier_query->fetch(PDO::FETCH_OBJ);
    $supplier_id = $line->supplier_id;

    $object = new CreateAsset($DB);
    $params =
        [
            'asset_name' => $post[0]['asset_name'],
            'asset_code' => $post[0]['asset_code'],
            'asset_nature' => $post[0]['asset_nature'],
            'location_id' => $location_id,
            'asset_status' => $post[0]['asset_status'],
            'asset_model' => $post[0]['asset_model'],
            'asset_category_id' => $asset_category_id,
            'supplier_id' => $supplier_id,
            'asset_description' => $post[0]['asset_description'],
            'asset_acquisition_price' =>  $post[0]['asset_acquisition_price'],
            'asset_service_start_date' => $post[0]['asset_service_start_date'],
            'asset_ff_1' => $post[0]['asset_ff_1'],
            'asset_ff_2' => $post[0]['asset_ff_2'],
            'function_id' => $function_id,
            'criticality_id' => $criticality_id,
            'asset_primary_code' => $post[0]['asset_primary_code'],
        ];
    $result_son = $object->execute($params);
    update_log($result_son);
} else {
    //criticality_code  换取id
    $criticality_query = $DB->prepare("
       SELECT  criticality_id
       FROM    mic_criticality
       WHERE criticality_code = :criticality_code
");
    $criticality_query->bindvalue(':criticality_code', $post[0]['criticality_code']);

    if (!$criticality_query->execute()) {
        Flight::error(new Exception(errorInfo($criticality_query)));
    }
    $items = [];
    $line = $criticality_query->fetch(PDO::FETCH_OBJ);
    $criticality_id = $line->criticality_id;

    //function_code 换取id
    $function_query = $DB->prepare("
       SELECT  function_id
       FROM    mic_function
       WHERE function_code = :function_code
");
    $function_query->bindvalue(':function_code', $post[0]['function_code']);

    if (!$function_query->execute()) {
        Flight::error(new Exception(errorInfo($function_query)));
    }
    $items = [];
    $line = $function_query->fetch(PDO::FETCH_OBJ);
    $function_id = $line->function_id;

    // 用location_code 换取id,
    $query = $DB->prepare("
       SELECT  location_id
       FROM    asset_location
       WHERE location_code = :location_code
");
    $query->bindvalue(':location_code', $post[0]['location_code']);

    if (!$query->execute()) {
        Flight::error(new Exception(errorInfo($query)));
    }
    $items = [];
    $line = $query->fetch(PDO::FETCH_OBJ);
    $location_id = $line->location_id;

    // 大类code换去大类id
    $category_query = $DB->prepare("
       SELECT  asset_category_id
       FROM    mic_asset_category
       WHERE asset_category_code = :asset_category_code
");
    $category_query->bindvalue(':asset_category_code', $post[0]['asset_category_code']);

    if (!$category_query->execute()) {
        Flight::error(new Exception(errorInfo($category_query)));
    }

    $line = $category_query->fetch(PDO::FETCH_OBJ);
    $asset_category_id = $line->asset_category_id;

    // 根据供应商code 获取供应商ID
    $pur_supplier_query = $DB->prepare("
       SELECT  supplier_id
       FROM    pur_supplier
       WHERE supplier_code = :supplier_code
");
    $pur_supplier_query->bindvalue(':supplier_code', $post[0]['supplier_code']);

    if (!$pur_supplier_query->execute()) {
        Flight::error(new Exception(errorInfo($pur_supplier_query)));
    }

    $line = $pur_supplier_query->fetch(PDO::FETCH_OBJ);
    $supplier_id = $line->supplier_id;

    $object = new CreateAsset($DB);
    $params =
        [
            'asset_name' => $post[0]['asset_name'],
            'asset_code' => $post[0]['asset_code'],
            'asset_nature' => $post[0]['asset_nature'],
            'location_id' => $location_id,
            'asset_status' => $post[0]['asset_status'],
            'asset_model' => $post[0]['asset_model'],
            'asset_category_id' => $asset_category_id,
            'supplier_id' => $supplier_id,
            'asset_description' => $post[0]['asset_description'],
            'asset_acquisition_price' =>  $post[0]['asset_acquisition_price'],
            'asset_service_start_date' => $post[0]['asset_service_start_date'],
            'asset_ff_1' => $post[0]['asset_ff_1'],
            'asset_ff_2' => $post[0]['asset_ff_2'],
            'function_id' => $function_id,
            'criticality_id' => $criticality_id,
            'asset_primary_code' => $post[0]['asset_primary_code'],
        ];
    $result_son = $object->execute($params);
    // 找父
    $parent_query = $DB->prepare("
    SELECT  asset_id
    FROM    asset_list
    WHERE   asset_primary_code = :asset_primary_code
");

    $parent_query->bindvalue(':asset_primary_code', $post[0]['asset_primary_code']);

    if (!$parent_query->execute()) {
        Flight::error(new Exception(errorInfo($parent_query)));
    } elseif ($parent_query->rowcount() == 0) {
        Flight::notFound();
    }
    $parent_query_line = $parent_query->fetch(PDO::FETCH_OBJ);
    if (!isset($parent_query_line->asset_id)) {
        echo '父编码不存在';
    } else {
        // 找子
        $son_query = $DB->prepare("
        SELECT  asset_id
        FROM    asset_list
        WHERE   asset_code = :asset_code
");
        $son_query->bindvalue(':asset_code', $result_son['asset_code']);

        if (!$son_query->execute()) {
            Flight::error(new Exception(errorInfo($son_query)));
        }

        $son_query_line = $son_query->fetch(PDO::FETCH_OBJ);

        $son_id = $son_query_line->asset_id;
        // 进行父子级同步
        $treeModel = new NestedSet($DB);
        $move_result = $treeModel->addChild($result_son['asset_id'], $parent_query_line->asset_id);
        $result = [
            'asset_id' => $son_id,
            'parent_id' =>$parent_query_line->asset_id,
            'details' => '父子级关系'
        ];
        update_log($result);
    }
}
CreateAsset  use case
<?php

namespace Domain\Asset\Register\UseCase;

use Domain\Asset\Register\Model\Register;
use PDO;
use Exception;
use Domain\UseCase;
use Domain\UseCaseInterface;
use InvalidArgumentException;
use Shared\Json;
use Shared\Exception\AlreadyExistsException;
use Overtrue\Pinyin\Pinyin;

class CreateAsset extends UseCase implements UseCaseInterface
{
    private $check;
    private $location;
    private $query;
    private $lpad;
    private $code;

    public function __construct(PDO $db)
    {
        $this->db = $db;

        $this->location = $this->db->prepare("
            SELECT location_id
            FROM asset_location
            WHERE location_code = :location_code
        ;");

        $this->check = $this->db->prepare("
            SELECT asset_code
            FROM asset_list
            WHERE asset_code = :asset_code
        ;");

        $this->query = $this->db->prepare("
            INSERT INTO asset_list (
                asset_nature, asset_code, asset_name, asset_name_pinyin, function_id, criticality_id,
                supplier_id, manufacturer_id, asset_cost_center_id, location_id,
                asset_structure_lft, asset_structure_rgt, asset_primary_code, asset_level,
                asset_category_id, asset_class_id, asset_type_id,
                asset_serial_number, asset_model, asset_status, asset_creation_time,
                asset_creator, asset_alternative_code, asset_ff_1, asset_ff_2, asset_ff_3,
                asset_ff_4, asset_ff_5, asset_ff_6, asset_ff_7, asset_ff_8, asset_ff_9, asset_ff_10,
                asset_ff_11, asset_ff_12, asset_ff_13, asset_ff_14, asset_ff_15
            )
            SELECT :asset_nature, :asset_code, :asset_name, :asset_name_pinyin, :function_id, :criticality_id, :supplier_id,
                   :manufacturer_id, :asset_cost_center_id, :location_id, IFNULL(MAX(asset_structure_rgt), 0) + 1,
                   IFNULL(MAX(asset_structure_rgt), 0) + 2, :asset_primary_code, 1, :asset_category_id, :asset_class_id, :asset_type_id,
                   :asset_serial_number, :asset_model, :asset_status, :asset_creation_time,@eamic_user, :asset_alternative_code,
                   :asset_ff_1, :asset_ff_2, :asset_ff_3, :asset_ff_4, :asset_ff_5, :asset_ff_6, :asset_ff_7,
                   :asset_ff_8, :asset_ff_9, :asset_ff_10, :asset_ff_11, :asset_ff_12, :asset_ff_13, :asset_ff_14, :asset_ff_15
            FROM asset_list
            WHERE location_id = :location_id
        ;");

        $this->lpad = $this->db->prepare("
            UPDATE asset_list
            SET asset_code = LPAD(asset_id, 5, 0)
            WHERE asset_id = :asset_id
            AND asset_code = ''
        ;");

        $this->code = $this->db->prepare("
            SELECT asset_code
            FROM asset_list
            WHERE asset_id = :asset_id
        ;");
    }

    public function execute(array $data)
    {
        if (!isset($data['asset_name'])) {
            throw new InvalidArgumentException('asset_name not provided');
        }

        if (isset($data['location_code'])) {
            $this->location->bindvalue(
                ':location_code',
                $data['location_code']
            );
            $this->location->execute();
            if ($this->location->rowCount() == 0) {
                throw new InvalidArgumentException(
                    $data['location_code'] . ' does not exist'
                );
            }
            $row = $this->location->fetch(PDO::FETCH_OBJ);
            $data['location_id'] = $row->location_id;
        } elseif (!isset($data['location_id'])) {
            throw new InvalidArgumentException(
                'location_id/location_code not provided'
            );
        }

        $data['asset_name_pinyin'] = null;
        // prettier-ignore
        if (class_exists('Overtrue\Pinyin\Pinyin')) {
            $pinyin = new Pinyin();
            $data['asset_name_pinyin'] = $pinyin->permalink($data['asset_name'], '');
        }

        $item = new Register($data);

        // Check if the code exists already
        $this->check->bindvalue(':asset_code', $item->asset_code);
        if (!$this->check->execute()) {
            throw new Exception(Json::errorInfo($this->check));
        } elseif ($this->check->rowCount() > 0 && $item->asset_code != '') {
            throw new AlreadyExistsException();
        }

        // prettier-ignore
        {
        $this->query->bindvalue(':location_id', $data['location_id'], PDO::PARAM_INT);
        $this->query->bindvalue(':asset_primary_code', $item->asset_code);
        $this->query->bindvalue(':asset_creation_time', Date('Y-m-d H:i:s'));
        $this->query->bindvalue(':asset_nature', $item->asset_nature, PDO::PARAM_INT);
        $this->query->bindvalue(':asset_code', $item->asset_code);
        $this->query->bindvalue(':asset_name', $item->asset_name);
        $this->query->bindvalue(':asset_name_pinyin', $data['asset_name_pinyin']);
        $this->query->bindvalue(':asset_model', $item->asset_model);
        $this->query->bindvalue(':function_id', $item->function_id, PDO::PARAM_INT);
        $this->query->bindvalue(':criticality_id', $item->criticality_id, PDO::PARAM_INT);
        $this->query->bindvalue(':supplier_id', $item->supplier_id, PDO::PARAM_INT);
        $this->query->bindvalue(':manufacturer_id', $item->manufacturer_id, PDO::PARAM_INT);
        $this->query->bindvalue(':asset_cost_center_id', $item->asset_cost_center_id, PDO::PARAM_INT);
        $this->query->bindvalue(':asset_serial_number', $item->asset_serial_number);
        $this->query->bindvalue(':asset_category_id', $item->asset_category_id, PDO::PARAM_INT);
        $this->query->bindvalue(':asset_class_id', $item->asset_class_id, PDO::PARAM_INT);
        $this->query->bindvalue(':asset_type_id', $item->asset_type_id, PDO::PARAM_INT);
        $this->query->bindvalue(':asset_status', $item->asset_status, PDO::PARAM_INT);
        $this->query->bindvalue(':asset_alternative_code', $item->asset_alternative_code);
        $this->query->bindvalue(':asset_ff_1', $item->asset_ff_1);
        $this->query->bindvalue(':asset_ff_2', $item->asset_ff_2);
        $this->query->bindvalue(':asset_ff_3', $item->asset_ff_3);
        $this->query->bindvalue(':asset_ff_4', $item->asset_ff_4);
        $this->query->bindvalue(':asset_ff_5', $item->asset_ff_5);
        $this->query->bindvalue(':asset_ff_6', $item->asset_ff_6);
        $this->query->bindvalue(':asset_ff_7', $item->asset_ff_7);
        $this->query->bindvalue(':asset_ff_8', $item->asset_ff_8);
        $this->query->bindvalue(':asset_ff_9', $item->asset_ff_9);
        $this->query->bindvalue(':asset_ff_10', $item->asset_ff_10);
        $this->query->bindvalue(':asset_ff_11', $item->asset_ff_11);
        $this->query->bindvalue(':asset_ff_12', $item->asset_ff_12);
        $this->query->bindvalue(':asset_ff_13', $item->asset_ff_13);
        $this->query->bindvalue(':asset_ff_14', $item->asset_ff_14);
        $this->query->bindvalue(':asset_ff_15', $item->asset_ff_15);
        }

        if (!$this->query->execute()) {
            throw new Exception(Json::errorInfo($this->query));
        }

        $new_id = $this->db->lastInsertId();

        $this->lpad->bindvalue(':asset_id', $new_id, PDO::PARAM_INT);
        if (!$this->lpad->execute()) {
            throw new Exception(Json::errorInfo($this->lpad));
        }

        // Get the asset code (it may have been changed by a trigger)
        $this->code->bindvalue(':asset_id', $new_id, PDO::PARAM_INT);
        if (!$this->code->execute()) {
            throw new Exception(Json::errorInfo($this->code));
        } elseif ($this->code->rowCount() == 0) {
            throw new Exception('The asset has not been created');
        }

        $item = $this->code->fetch(PDO::FETCH_OBJ);

        $asset_code = $item->asset_code;

        return [
            'asset_id' => $new_id,
            'asset_code' => $asset_code,
        ];
    }
}
NestedSet  
<?php
/**
 * PDONestedSet - Using Nested Sets Pattern to Model Tree Structure in PHP
 * PHP Version 5.0.0
 * Version 5.6.4
 * @package PDONestedSet
 * @link https://github.com/ben-nsng/php-pdo-nested-set
 * @author Ngai Sing Ng (Ben) <ben.nsng@gmail.com>
 * @copyright 2015 Ngai Sing Ng
 * @license The MIT License (MIT)
 * @note This program is distributed in the hope that it will be useful - WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.
 */

namespace {

    Class NestedSet {

        /**
         * Database object
         * @type resource
         */
        private $database;

        /**
         * Table name
         * @type string
         */
        private $table = 'asset_list';

        /**
         * Constructor, defined PDO object
         * @param object $dbh
         */
        public function __construct(PDO $dbh) {
            $this->database = new PDONestedSet\database($dbh);
        }

        /**
         * Change the current table to manage tree structure
         * @param object $table table name
         */
        public function changeTable($table) {
            $this->table = $table;
        }

        /**
         * Add root to the table (for initialization only)
         */
        public function addRoot() {
            $sql = 'SELECT COUNT(1) AS row_count FROM asset_list WHERE asset_level=0;';

            $query = $this->database->execute($sql);

            $result = $query->result();
            if($result[0]->row_count != '0') {
                return false;    // root exists, exit
            }

            $sql = 'INSERT INTO asset_list(location_name, asset_structure_lft, asset_structure_rgt, asset_level) VALUES(?, ?, ?, ?)';

            $query = $this->database->execute($sql, array('root', '1', '2', '0'));
        }

        /**
         * Add new node to the tree structure
         * @param string $location_name node name
         * @param int $node_parent_id parent node asset_id
         * @return int new node asset_id
         */
        public function addNode($location_name = '', $node_parent_id = '') {

            //if no parent define, add to root node
            if($node_parent_id == '') {
                $sql = 'SELECT asset_id FROM asset_list WHERE asset_level=0';
                $query = $this->database->execute($sql);

                // check if root node exists
                if($query->numRows() == 0) {
                    $this->addRoot();
                    return $this->addNode($location_name, $node_parent_id);
                }

                $result = $query->result();
                $node_parent_id = $result[0]->asset_id;
            }

            //check if node_parent_id exists
            $sql = 'SELECT asset_id, asset_structure_lft, asset_structure_rgt, asset_level FROM asset_list WHERE asset_id = ?';
            $query = $this->database->execute($sql, array($node_parent_id));
            if($query->numRows() == 0) {
                return false;    // no parent ?
            }

            $result = $query->result();
            $parent_lft = $result[0]->asset_structure_lft;
            $parent_rht = $result[0]->asset_structure_rgt;
            $parent_lvl = $result[0]->asset_level;

            $this->database->transStart();

            //shift the node to give some room for new node
            $sql = 'UPDATE asset_list
            SET
                asset_structure_lft = CASE
                    WHEN asset_structure_lft > ? THEN asset_structure_lft + 2
                    ELSE asset_structure_lft
                END,
                asset_structure_rgt = CASE
                    WHEN asset_structure_rgt >= ? THEN asset_structure_rgt + 2
                    ELSE asset_structure_rgt
                END
            WHERE
                (asset_nature = 0 OR asset_nature = 1)
            AND
                asset_structure_rgt >= ?';
            $this->database->execute($sql, array($parent_rht, $parent_rht, $parent_rht));

            $sql = 'INSERT INTO asset_list(location_name, asset_structure_lft, asset_structure_rgt, asset_level, asset_parent_id) VALUES(?, ?, ?, ?, ?)';
            $this->database->execute($sql, array($location_name, $parent_rht, $parent_rht + 1, $parent_lvl + 1, $node_parent_id));

            $this->database->transEnd();

            return $this->database->lastInsertId();
        }

        /**
         * Select all nodes from the table
         */
        public function selectAll() {
            $sql = 'SELECT asset_id, location_name, asset_level, asset_parent_id,
            FORMAT((((asset_structure_rgt - asset_structure_lft) -1) / 2),0) AS cnt_children,
            CASE WHEN asset_structure_rgt - asset_structure_lft > 1 THEN 1 ELSE 0 END AS is_branch
            FROM asset_list ORDER BY asset_structure_lft';
            return $this->database->execute($sql);
        }

        /**
         * Move existing node into node 2
         * @param int $node_id_1 asset_id of node 1 SOURCE
         * @param int $node_id_2 asset_id of node 2 TARGET
         */
        public function addChild($node_id_1, $node_id_2) {
            if($node_id_1 == $node_id_2) {
                return false;    //same node
            }

            // check if node asset_id 1, 2 exist
            $sql = 'SELECT     asset_id, asset_structure_lft, asset_structure_rgt, asset_level,
                            @myLocation := location_id, asset_primary_code
                    FROM asset_list
                    WHERE asset_id = ? OR asset_id = ?';
            $query = $this->database->execute($sql, array($node_id_1, $node_id_2));

            if($query->numRows() != 2) {
                return false;    //no node
            }

            // save the result
            $result = $query->result();
            if($result[0]->asset_id == $node_id_1) {
                $node1 = $result[0];
                $node2 = $result[1];
            }
            else {
                $node1 = $result[1];
                $node2 = $result[0];
            }

            $node1_size = $node1->asset_structure_rgt - $node1->asset_structure_lft + 1;

            $this->database->transStart();

            // temporary "remove" moving node
            $sql = 'UPDATE asset_list
                    SET asset_structure_lft = 0 - asset_structure_lft,
                        asset_structure_rgt = 0 - asset_structure_rgt,
                        asset_level = asset_level + (?),
                        asset_primary_code = ?
                    WHERE asset_structure_lft >= ? AND asset_structure_rgt <= ?
                    AND (asset_nature = 0 OR asset_nature = 1)
                    AND location_id = @myLocation';
            $this->database->execute($sql, array($node2->asset_level - $node1->asset_level + 1,
                                                 $node2->asset_primary_code,
                                                 $node1->asset_structure_lft,
                                                 $node1->asset_structure_rgt));

            // decrease left / right position for current node
            $sql = 'UPDATE asset_list
                    SET asset_structure_lft = asset_structure_lft - (?)
                    WHERE asset_structure_lft >= ?
                    AND (asset_nature = 0 OR asset_nature = 1)
                    AND location_id = @myLocation';
            $this->database->execute($sql, array($node1_size, $node1->asset_structure_lft));

            $sql = 'UPDATE asset_list
                    SET asset_structure_rgt = asset_structure_rgt - (?)
                    WHERE asset_structure_rgt >= ?
                    AND (asset_nature = 0 OR asset_nature = 1)
                    AND location_id = @myLocation';
            $this->database->execute($sql, array($node1_size, $node1->asset_structure_rgt));

            // increase left / right position for future node
            $sql = 'UPDATE asset_list
                    SET asset_structure_lft = asset_structure_lft + (?)
                    WHERE asset_structure_lft >= ?
                    AND (asset_nature = 0 OR asset_nature = 1)
                    AND location_id = @myLocation';
            $this->database->execute($sql, array($node1_size, $node2->asset_structure_rgt > $node1->asset_structure_rgt ? $node2->asset_structure_rgt - $node1_size : $node2->asset_structure_rgt));

            $sql = 'UPDATE asset_list
                    SET asset_structure_rgt = asset_structure_rgt + (?)
                    WHERE asset_structure_rgt >= ?
                    AND (asset_nature = 0 OR asset_nature = 1)
                    AND location_id = @myLocation';
            $this->database->execute($sql, array($node1_size, $node2->asset_structure_rgt > $node1->asset_structure_rgt ? $node2->asset_structure_rgt - $node1_size : $node2->asset_structure_rgt));

            // move the node to new position
            $sql = 'UPDATE asset_list
                    SET asset_structure_lft = 0 - asset_structure_lft + (?),
                        asset_structure_rgt = 0 - asset_structure_rgt + (?)
                    WHERE asset_structure_lft <= ? AND asset_structure_rgt >= ?
                    AND (asset_nature = 0 OR asset_nature = 1)
                    AND location_id = @myLocation';
            $this->database->execute($sql, array(
                $node2->asset_structure_rgt > $node1->asset_structure_rgt ? $node2->asset_structure_rgt - $node1->asset_structure_rgt - 1 : $node2->asset_structure_rgt - $node1->asset_structure_rgt - 1 + $node1_size,
                $node2->asset_structure_rgt > $node1->asset_structure_rgt ? $node2->asset_structure_rgt - $node1->asset_structure_rgt - 1 : $node2->asset_structure_rgt - $node1->asset_structure_rgt - 1 + $node1_size,
                0 - $node1->asset_structure_lft, 0 - $node1->asset_structure_rgt));

            // update parent
            $sql = 'UPDATE asset_list
                    SET asset_parent_id = ?
                    WHERE asset_id = ?
                    AND location_id = @myLocation';
            $this->database->execute($sql, array($node2->asset_id, $node1->asset_id));

            $this->database->transEnd();
        }

        /**
         * Move existing node before node 2
         * @param int $node_id_1 asset_id of node 1 SOURCE
         * @param int $node_id_2 asset_id of node 2 TARGET
         */
        public function addBefore($node_id_1, $node_id_2) {
            if($node_id_1 == $node_id_2) {
                return false;    //same node
            }

            // check if node asset_id 1, 2 exist
            $sql = 'SELECT     asset_id, asset_structure_lft, asset_structure_rgt, asset_level, asset_parent_id,
                            @myLocation := location_id, asset_code, asset_primary_code
                    FROM asset_list
                    WHERE asset_id = ? OR asset_id = ?';
            $query = $this->database->execute($sql, array($node_id_1, $node_id_2));

            if($query->numRows() != 2) {
                return false;    //no node
            }

            // save the result
            $result = $query->result();
            if($result[0]->asset_id == $node_id_1) {
                $node1 = $result[0];
                $node2 = $result[1];
            }
            else {
                $node1 = $result[1];
                $node2 = $result[0];
            }

            $this->database->transStart();

            if ($node2->asset_level == 1 || $node2->asset_parent_id == 0) {
                // same level, put node 1 before node 2
                $node1_size = $node1->asset_structure_rgt - $node1->asset_structure_lft + 1;
                $node2_size = $node2->asset_structure_rgt - $node1->asset_structure_lft + 1;

                $sql = 'SELECT @right_max :=  MAX(asset_structure_rgt)
                        FROM asset_list
                        WHERE location_id = @myLocation
                        AND asset_nature IN (1 , 0);

                        UPDATE asset_list
                        SET asset_structure_lft = @right_max + asset_structure_lft - (? - 1),
                            asset_structure_rgt = @right_max + asset_structure_rgt - (? - 1),
                            asset_level = asset_level - (? - 1),
                            asset_primary_code = ?
                        WHERE asset_structure_lft >= ? AND asset_structure_rgt <= ?
                        AND (asset_nature = 0 OR asset_nature = 1)
                        AND location_id = @myLocation';

                $this->database->execute($sql, array($node1->asset_structure_lft,
                                                     $node1->asset_structure_lft,
                                                     $node1->asset_level,
                                                     $node1->asset_code,
                                                     $node1->asset_structure_lft,
                                                     $node1->asset_structure_rgt));

                // shift other node to correct position
                $sql = 'UPDATE asset_list
                        SET asset_structure_lft = CASE WHEN asset_structure_lft > ? THEN asset_structure_lft - ? ELSE asset_structure_lft END,
                            asset_structure_rgt = CASE WHEN asset_structure_rgt >= ? THEN asset_structure_rgt - ? ELSE asset_structure_rgt END
                        WHERE asset_structure_rgt >= ?
                        AND (asset_nature = 0 OR asset_nature = 1)
                        AND location_id = @myLocation';
                $this->database->execute($sql, array($node1->asset_structure_lft, $node1_size, $node1->asset_structure_rgt, $node1_size, $node1->asset_structure_rgt));

                // update parent
                $sql = 'UPDATE asset_list
                        SET asset_parent_id = 0
                        WHERE asset_id = ?
                        AND location_id = @myLocation';
                $this->database->execute($sql, array($node1->asset_id));

            } else {
                // if not in same level, put it in same levels
                if($node1->asset_level != $node2->asset_level || $node1->asset_parent_id != $node2->asset_parent_id) {
                    $this->addChild($node_id_1, $node2->asset_parent_id);
                    return $this->addBefore($node_id_1, $node_id_2);
                }

                // same level, put node 1 before node 2
                $node1_size = $node1->asset_structure_rgt - $node1->asset_structure_lft + 1;
                $node2_size = $node2->asset_structure_rgt - $node1->asset_structure_lft + 1;

                // temporary "remove" moving node
                $sql = 'UPDATE asset_list
                        SET asset_structure_lft = 0 - asset_structure_lft,
                            asset_structure_rgt = 0 - asset_structure_rgt
                        WHERE asset_structure_lft >= ? AND asset_structure_rgt <= ?
                        AND (asset_nature = 0 OR asset_nature = 1)
                        AND location_id = @myLocation';

                $this->database->execute($sql, array($node1->asset_structure_lft, $node1->asset_structure_rgt));

                if($node1->asset_structure_lft > $node2->asset_structure_lft) {    //move left

                    //shift the node to right to give some room
                    $sql = 'UPDATE asset_list
                            SET asset_structure_lft = asset_structure_lft + ?,
                                asset_structure_rgt = asset_structure_rgt + ?
                            WHERE asset_structure_lft >= ? AND asset_structure_rgt <= ?
                            AND (asset_nature = 0 OR asset_nature = 1)
                            AND location_id = @myLocation';
                     $this->database->execute($sql, array($node1_size, $node1_size, $node2->asset_structure_lft, $node1->asset_structure_lft));

                    //move back the node1
                    $sql = 'UPDATE asset_list
                            SET asset_structure_lft = 0 - asset_structure_lft - ?,
                                asset_structure_rgt = 0 - asset_structure_rgt - ?
                            WHERE asset_structure_lft <= ? AND asset_structure_rgt >= ?
                            AND (asset_nature = 0 OR asset_nature = 1)
                            AND location_id = @myLocation';
                     $this->database->execute($sql, array($node1->asset_structure_lft - $node2->asset_structure_lft, $node1->asset_structure_lft - $node2->asset_structure_lft, 0 - $node1->asset_structure_lft, 0 - $node1->asset_structure_rgt));
                }

                else {

                    //shift the node to left to give some room
                    $sql = 'UPDATE asset_list
                            SET asset_structure_lft = asset_structure_lft - ?,
                                asset_structure_rgt = asset_structure_rgt - ?
                            WHERE asset_structure_lft >= ? AND asset_structure_rgt < ?
                            AND (asset_nature = 0 OR asset_nature = 1)
                            AND location_id = @myLocation';
                     $this->database->execute($sql, array($node1_size, $node1_size, $node1->asset_structure_rgt, $node2->asset_structure_lft));

                    //move back the node1
                    $sql = 'UPDATE asset_list
                            SET asset_structure_lft = 0 - asset_structure_lft + ?,
                                asset_structure_rgt = 0 - asset_structure_rgt + ?
                            WHERE asset_structure_lft <= ? AND asset_structure_rgt >= ?,
                            AND (asset_nature = 0 OR asset_nature = 1)
                            AND location_id = @myLocation';
                     $this->database->execute($sql, array($node2->asset_structure_lft - $node1->asset_structure_rgt - 1, $node2->asset_structure_lft - $node1->asset_structure_rgt - 1, 0 - $node1->asset_structure_lft, 0 - $node1->asset_structure_rgt));

                }
            }
            $this->database->transEnd();
        }

        /**
         * Move existing node after node 2
         * @param int $node_id_1 asset_id of node 1
         * @param int $node_id_2 asset_id of node 2
         */
        public function addAfter($node_id_1, $node_id_2) {

            if($node_id_1 == $node_id_2) {
                return false;    //same node
            }

            // check if node asset_id 1, 2 exist
            $sql = 'SELECT asset_id, asset_structure_lft, asset_structure_rgt, asset_level, asset_parent_id,
                            @myLocation := location_id
                    FROM asset_list WHERE asset_id=? OR asset_id=?';
            $query = $this->database->execute($sql, array($node_id_1, $node_id_2));

            if($query->numRows() != 2) {
                return false;    //no node
            }

            // save the result
            $result = $query->result();
            if($result[0]->asset_id == $node_id_1) {
                $node1 = $result[0];
                $node2 = $result[1];
            }
            else {
                $node1 = $result[1];
                $node2 = $result[0];
            }

            $this->database->transStart();

            // if not in same level, put it in same level
            if($node1->asset_level != $node2->asset_level || $node1->asset_parent_id != $node2->asset_parent_id) {
                $this->addChild($node_id_1, $node2->asset_parent_id);
                return $this->addAfter($node_id_1, $node_id_2);
            }

            // same level, put node 1 before node 2
            $node1_size = $node1->asset_structure_rgt - $node1->asset_structure_lft + 1;
            $node2_size = $node2->asset_structure_rgt - $node1->asset_structure_lft + 1;

            // temporary "remove" moving node
            $sql = 'UPDATE asset_list
                    SET asset_structure_lft = 0 - asset_structure_lft,
                        asset_structure_rgt = 0 - asset_structure_rgt
                    WHERE asset_structure_lft >= ? AND asset_structure_rgt <= ?
                    AND (asset_nature = 0 OR asset_nature = 1)
                    AND location_id = @myLocation';

            $this->database->execute($sql, array($node1->asset_structure_lft, $node1->asset_structure_rgt));

            if($node1->asset_structure_lft > $node2->asset_structure_lft) {    //move left

                //shift the node to right to give some room
                $sql = 'UPDATE asset_list
                        SET asset_structure_lft = asset_structure_lft + ?,
                            asset_structure_rgt = asset_structure_rgt + ?
                        WHERE asset_structure_lft > ? AND asset_structure_rgt <= ?
                        AND (asset_nature = 0 OR asset_nature = 1)
                        AND location_id = @myLocation';
                 $this->database->execute($sql, array($node1_size, $node1_size, $node2->asset_structure_rgt, $node1->asset_structure_lft));

                //move back the node1
                $sql = 'UPDATE asset_list
                        SET asset_structure_lft = 0 - asset_structure_lft - ?,
                            asset_structure_rgt = 0 - asset_structure_rgt - ?
                        WHERE asset_structure_lft <= ? AND asset_structure_rgt >= ?
                        AND (asset_nature = 0 OR asset_nature = 1)
                        AND location_id = @myLocation';
                 $this->database->execute($sql, array($node1->asset_structure_lft - $node2->asset_structure_rgt - 1, $node1->asset_structure_lft - $node2->asset_structure_rgt - 1, 0 - $node1->asset_structure_lft, 0 - $node1->asset_structure_rgt));
            }

            else {

                //shift the node to left to give some room
                $sql = 'UPDATE asset_list
                        SET asset_structure_lft = asset_structure_lft - ?,
                            asset_structure_rgt = asset_structure_rgt - ?
                        WHERE asset_structure_lft >= ? AND asset_structure_rgt <= ?
                        AND (asset_nature = 0 OR asset_nature = 1)
                        AND location_id = @myLocation';
                 $this->database->execute($sql, array($node1_size, $node1_size, $node1->asset_structure_rgt, $node2->asset_structure_rgt));

                //move back the node1
                $sql = 'UPDATE asset_list
                        SET asset_structure_lft = 0 - asset_structure_lft + ?,
                            asset_structure_rgt = 0 - asset_structure_rgt + ?
                        WHERE asset_structure_lft <= ? AND asset_structure_rgt >= ?
                        AND (asset_nature = 0 OR asset_nature = 1)
                        AND location_id = @myLocation';
                 $this->database->execute($sql, array($node2->asset_structure_rgt - $node1->asset_structure_rgt, $node2->asset_structure_rgt - $node1->asset_structure_rgt, 0 - $node1->asset_structure_lft, 0 - $node1->asset_structure_rgt));

            }

            $this->database->transEnd();
        }

        /**
         * Delete existing node
         * @param int $node_id asset_id of node
         */
        public function deleteNode($node_id) {

            $sql = 'SELECT asset_id, asset_structure_lft, asset_structure_rgt, asset_level,
                            @myLocation := location_id
                    FROM asset_list WHERE asset_id=?';
            $query = $this->database->execute($sql, $node_id);

            if($query->numRows() == 0) {
                return false;    //no node
            }

            $result = $query->result();
            $asset_structure_lft = $result[0]->asset_structure_lft;
            $asset_structure_rgt = $result[0]->asset_structure_rgt;
            $asset_level = $result[0]->asset_level;

            $this->database->transStart();

            // remove parent first
            $sql = 'UPDATE asset_list
                    SET asset_parent_id = NULL
                    WHERE asset_structure_lft >= ? AND asset_structure_rgt <= ?
                    AND location_id = @myLocation';
            $this->database->execute($sql, array($asset_structure_lft, $asset_structure_rgt));


            // delete nodes
            /*
            $sql = 'DELETE *
                  FROM asset_list
                 WHERE asset_structure_lft >= ?
                   AND asset_structure_rgt <= ?';
            $this->database->execute($sql, array($asset_structure_lft, $asset_structure_rgt));
            */
            $sql = 'DELETE
                    FROM asset_list
                    WHERE asset_parent_id IS NULL AND asset_level <> 0
                    AND location_id = @myLocation';
            $this->database->execute($sql);

            $node_tmp = $asset_structure_rgt - $asset_structure_lft + 1;

            // shift other node to correct position
            $sql = 'UPDATE asset_list
                    SET asset_structure_lft = CASE WHEN asset_structure_lft > ? THEN asset_structure_lft - ? ELSE asset_structure_lft END,
                        asset_structure_rgt = CASE WHEN asset_structure_rgt >= ? THEN asset_structure_rgt - ? ELSE asset_structure_rgt END
                    WHERE asset_structure_rgt >= ?
                    AND (asset_nature = 0 OR asset_nature = 1)
                    AND location_id = @myLocation';
            $this->database->execute($sql, array($asset_structure_lft, $node_tmp, $asset_structure_rgt, $node_tmp, $asset_structure_rgt));

            $this->database->transEnd();
        }

    }

}

namespace PDONestedSet {

    class database {

        private $dh;
        private $trans;

        public function __construct(\PDO $dbh) {
            $this->dh = $dbh;
            $this->trans = false;
        }

        public function lastInsertId() {
            return $this->dh->lastInsertId();
        }

        public function transStart() {
            if($this->trans) return;
            $this->trans = true;
            $this->dh->beginTransaction();
        }

        public function transEnd() {
            $this->trans = false;
            $this->dh->commit();
        }

        public function execute($sql, $placeholders = array()) {
            $stmt = new statement($this->dh);
            return $stmt->query($sql, $placeholders);
        }

    }

    class statement {
        private $dh;
        private $stmt;
        private $result;
        private $result_array;

        public function __construct($dh) {
            $this->dh = $dh;
        }

        public function query($sql, $placeholders = array()) {
            if(count($placeholders) == 0)
                $this->stmt = $this->dh->query($sql);
            else {
                if(!is_array($placeholders)) $placeholders = array($placeholders);
                $this->stmt = $this->dh->prepare($sql);
                $this->stmt->execute($placeholders);
            }

            return $this;
        }

        public function result($array = false) {
            if(!$array && $this->result != null) return $this->result;
            if($array && $this->result_array != null) return $this->result_array;
            if($this->stmt != null) {
                if(!$array) {
                    $this->result = $this->stmt->fetchAll(\PDO::FETCH_OBJ);
                    return $this->result;
                }
                else {
                    $this->result_array = $this->stmt->fetchAll(\PDO::FETCH_ASSOC);
                    return $this->result_array;
                }
            }
            return array();
        }

        public function numRows() {
            if($this->stmt != null) return $this->stmt->rowCount();
            return 0;
        }
    }

}

 

posted @ 2022-10-14 11:14  王越666  阅读(20)  评论(0编辑  收藏  举报