phalconplus Documentation v1.0.0-beta
Class
Class PhalconPlus Db

# UnitOfWork

    //objects = new SplObjectStorage();
            let this->dbServiceName = dbServiceName;
        }

        public function save(var name, <\PhalconPlus\Base\Model> model, array initial_data = [])
        {
            if !empty initial_data {
                model->assign(initial_data);
            }
            if !model->exists() {
                this->insert(name, model, initial_data, false);
            } else {
                this->update(name, model, initial_data, false);
            }
        }

        public function insert(var name, <\Phalcon\Mvc\Model> model, array initial_data = [], boolean assign = true)
        {
            if !empty initial_data && assign == true {
                model->assign(initial_data);
            }
            this->detach(model);
            this->attach(model, [
                "method" : "insert",
                "name" : name,
                "initial_data" : initial_data
            ]);
        }

        public function update(var name, <\Phalcon\Mvc\Model> model, array initial_data = [], boolean assign = true)
        {
            if !empty initial_data && assign == true {
                model->assign(initial_data);
            }
            this->detach(model);
            this->attach(model, [
                "method" : "update",
                "name" : name,
                "initial_data" : initial_data
            ]);
        }

        public function delete(var name, <\Phalcon\Mvc\Model> model)
        {
            this->detach(model);
            this->attach(model, [
                "method" : "delete",
                "name" : name
            ]);
        }

        protected function attach(var model, var info)
        {
            this->objects->attach(model, info);
        }

        public function detach(model)
        {
            this->objects->detach(model);
        }

        public function exec()
        {
            let this->exception = null;
            let this->failed = null;
            let this->deleted = new SplObjectStorage();
            let this->inserted = new SplObjectStorage();
            let this->updated = new SplObjectStorage();

            var txManager, transaction, e;

            let txManager = new TxManager();
            txManager->setDbService(this->dbServiceName);
            let transaction = txManager->get();

            var obj, info;
            this->objects->rewind();
            try {
                while(this->objects->valid()) {
                    let obj = this->objects->current();
                    let info = this->objects->getInfo();

                    var method, name;
                    let method = info["method"];
                    let name = info["name"];

                    unset(info["method"]); unset(info["name"]);

                    obj->setTransaction(transaction);

                    var newMethod;
                    let newMethod = "exec".ucfirst(method);
                    if (this->{newMethod}(obj, info) == false) {
                        transaction->rollback("Model exec failed: " . name . ":" . method);
                    }
                    this->objects->next();
                }
                transaction->commit();
            } catch TxFailed, e {
                let this->failed = obj;
                let this->exception = e;
                return false;
            }
            return true;
        }

        public function execInsert(<\Phalcon\Mvc\Model> model, array info)
        {
            var initial_data, result, last_insert_id;
            let initial_data = info["initial_data"];
            if !empty(initial_data) {
                var col, val;
                for col, val in initial_data {
                    if is_callable(val) {
                        let initial_data[col] = {val}();
                    }
                }
                let result = model->create(initial_data);
            } else {
                let result = model->create();
            }
            if result == true {
                let last_insert_id = model->getWriteConnection()->lastInsertId();
                this->inserted->attach(model, [
                    "last_insert_id" : last_insert_id
                ]);
            }
            return result;
        }

        public function execUpdate(<\Phalcon\Mvc\Model> model, array info = [])
        {
            var result, initial_data, metaData, columnMap, whiteList, attrField;
            let whiteList = [];

            // 过滤所有不需要更新（值为NULL）的字段，
            // 通过欺骗Model->_doLowUpdate()来达到此目的，要求必须useDynamicUpdate()和keepSnapshot()
            let metaData = model->getModelsMetaData();
            let columnMap = metaData->getColumnMap(model);
            if typeof columnMap == "array" {
                for _, attrField in columnMap {
                    if empty this->{attrField} {
                        let whiteList[attrField] = null;
                    }
                }
            }
            model->setSnapshotData(whiteList); // 实际上我们用了columnMap之后的字段作为data

            let initial_data = info["initial_data"];

            if(!empty(initial_data)) {
                var col, val;
                for col, val in initial_data {
                    if is_callable(val) {
                        let initial_data[col] = {val}();
                    }
                    if is_null(val) {
                        unset(initial_data[col]);
                    }
                }
                let result = model->update(initial_data);
            } else {
                let result = model->update();
            }
            if result == true {
                this->updated->attach(model);
            }
            return result;
        }

        public function execDelete(<\Phalcon\Mvc\Model> model, array info = [])
        {
            var result;
            let result = model->delete();
            if result == true {
                this->deleted->attach(model);
            }
            return result;
        }

        public function getObjects()
        {
            return this->objects;
        }

        public function getInserted()
        {
            return this->inserted;
        }

        public function getUpdated()
        {
            return this->updated;
        }

        public function getDeleted()
        {
            return this->deleted;
        }

        public function getException()
        {
            return this->exception;
        }

        public function getFailed()
        {
            return this->failed;
        }
    }