/***************************** {{{ LICENSE ********************************\ * dbobj, the relational object persistence module for PHP * * Copyright (C) 2006 Adam Banko * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software * * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * \***************************** LICENSE }}} ********************************/ #include "dbobj.h" #include "zend_exceptions.h" #include "zend.h" #include "SQL.h" #include "intermediate.h" #include "dbTypes.h" #include "objTypes.h" #include "objType/relation.h" #include "dbType/serial.h" #include "dbobjIterator.h" #include "byteorder.h" #include "localClassConfig.h" #include "dbDriver.h" static zend_function_entry php_dbobj_class_functions[] = { PHP_ME(dbobj, save, NULL, ZEND_ACC_PUBLIC) PHP_ME(dbobj, delete_on_save, NULL, ZEND_ACC_PUBLIC) PHP_ME(dbobj, is_in_database, NULL, ZEND_ACC_PUBLIC) {NULL, NULL, NULL} }; zend_class_entry *dbobj_class_entry_ptr; //{{{ #define ZDGETTHIS() (get_this_dbobj(this_ptr)) #define ZDTHIS (get_this_dbobj(zObject)) #define get_this_dbobj(zobject) ((dbobj)zend_object_store_get_object(zobject TSRMLS_CC)) //}}} //{{{<> //{{{ //{{{create_UID_from_dbPropPKs static uidT create_UID_from_dbPropPKs(classConfig cConf, dbProp PKs[], uint PKsL) { uidT uid; char *className = cConf->className; uint classNameL = cConf->classNameL; uint i; uint PKsS; uint uidL; char *outPKptr; classNameL++; // with trailing '\0' PKsS = sizeof(uint)*PKsL; //Size of PKs for(i = 0; i < PKsL; i++) { PKsS += CALM(PKs[i]->config->dbType, serialize_getLen, PKs[i]->value); } uidL = UID_SIZE(classNameL, PKsS); uid = emalloc(uidL); uid->classNameL = classNameL - 1;//without '\0' uid->uidL = uidL; strncpy(uid->data, className, classNameL); outPKptr = uid->data + classNameL; for(i = 0; i < PKsL; i++) { uint *outPKptr_size = (uint*) outPKptr; char *new_outPKptr; outPKptr += sizeof(*outPKptr_size); new_outPKptr = CALM(PKs[i]->config->dbType, serialize, outPKptr, PKs[i]->value); *outPKptr_size = new_outPKptr - outPKptr; outPKptr = new_outPKptr; } assert((char*)outPKptr - (char*)uid == uidL); return uid; }//}}} //{{{create_UID_from_dbValPKs static uidT create_UID_from_dbValPKs(classConfig cConf, dbVal PKs[], uint PKsL) { uidT uid; char *className = cConf->className; uint classNameL = cConf->classNameL + 1;// with trailing '\0' uint PKsS = sizeof(uint)*PKsL; //Size of PKs uint uidL; char *outPKptr; uint i; for(i = 0; i < PKsL; i++) { PKsS += CALM(cConf->PKs[i]->dbType, serialize_getLen, PKs[i]); } uidL = UID_SIZE(classNameL, PKsS); uid = emalloc(uidL); uid->classNameL = classNameL - 1;//without '\0' uid->uidL = uidL; strncpy(uid->data, className, classNameL); outPKptr = uid->data + classNameL; for(i = 0; i < PKsL; i++) { uint *outPKptr_size = (uint*) outPKptr; char *new_outPKptr; outPKptr += sizeof(uint); new_outPKptr = CALM(cConf->PKs[i]->dbType, serialize, outPKptr, PKs[i]); *outPKptr_size = new_outPKptr - outPKptr; outPKptr = new_outPKptr; } return uid; }//}}} //}}} //{{{zConditions2Conditons(...) static uint zConditions2Conditons(dbCondition **conditions, classConfig cConf, zval *zConditions TSRMLS_DC) { zval **retP; HashPosition p; uint condL = 0; HashTable *condH; dbCondition *conditionCursor; if(Z_TYPE_P(zConditions) != IS_ARRAY) DBOBJ_ERROR_CRIT("zConditions2Conditons: $conditions veriable is not an array"); condH = Z_ARRVAL_P(zConditions); //count condL (the number of the dbConditions) for( zend_hash_internal_pointer_reset_ex(condH, &p); zend_hash_get_current_data_ex(condH, (void**) &retP, &p) == SUCCESS; zend_hash_move_forward_ex(condH, &p)) { char *condKey; uint condKeyL; //get Key if (zend_hash_get_current_key_ex(condH, &condKey, &condKeyL, NULL, 0, &p) != HASH_KEY_IS_STRING) DBOBJ_ERROR( "zConditions2Conditons: nem asszociativ feltétel tömb"); //get objVal { condKeyL -= sizeof(""); objPropConfig objConf = classConfig_get_objPropConfig_handle_error(cConf, STRINGLU(condKey) TSRMLS_CC); switch (objConf->Class) { case OBJPROP_BASIC: condL++; //basic objProp will resolv to one condition break; case OBJPROP_COMPLEX: condL += ((complexPropConfig)objConf)->sourcesL; break; } } } if(!condL) { *conditions = NULL; return condL; } *conditions = emalloc(sizeof(**conditions) * condL); conditionCursor = *conditions; //fill conditions array for( zend_hash_internal_pointer_reset_ex(condH, &p); zend_hash_get_current_data_ex(condH, (void**) &retP, &p) == SUCCESS; zend_hash_move_forward_ex(condH, &p)) { char *condKey; uint condKeyL; //get Key if (zend_hash_get_current_key_ex(condH, &condKey, &condKeyL, NULL, 0, &p) != HASH_KEY_IS_STRING) assert(0); // { condKeyL -= sizeof(""); //get objVal objPropConfig objPropConf = classConfig_get_objPropConfig_handle_error(cConf, STRINGLU(condKey) TSRMLS_CC); objType type = objPropConf->type; objVal ov; assert(objPropConf->Class == OBJPROP_BASIC || !is_objType_relation(type)); //having relation as condition is insane ov = CALM(type, zVal2objVal, *retP TSRMLS_CC); //get dbVals switch(objPropConf->Class) { case OBJPROP_BASIC: { basicPropConfig basicPropConf = (basicPropConfig)objPropConf; conditionCursor->config = basicPropConf; conditionCursor->value = CALM(basicPropConf->dbType, basicVal2dbVal, (basicVal)ov); conditionCursor++; break; } case OBJPROP_COMPLEX: { complexPropConfig complexPropConf = (complexPropConfig)objPropConf; basicVal* basicVals = CALM(complexPropConf->type, complexVal2basicVals, (complexVal)ov TSRMLS_CC); uint i; for(i = 0; i < complexPropConf->sourcesL; i++) { basicPropConfig basicPropConf = complexPropConf->sources[i]; conditionCursor->config = basicPropConf; conditionCursor->value = CALM(basicPropConf->dbType, basicVal2dbVal, basicVals[i]); conditionCursor++; } efree(basicVals); break; } } CALM(type, objVal_dtor, ov TSRMLS_CC); } } return condL; }//}}} //{{{zLoad2Load(...) static uint zLoad2Load(basicPropConfig *(retLoad[]), classConfig classConf, zval *zLoad TSRMLS_DC) { zval **retP; HashPosition p; HashTable *loadH; uint loadL; basicPropConfig *ret; if(Z_TYPE_P(zLoad) != IS_ARRAY) DBOBJ_ERROR_CRIT("zLoad2Load: load not array"); loadH = Z_ARRVAL_P(zLoad); loadL = zend_hash_num_elements(loadH); ret = *retLoad = emalloc(sizeof(**retLoad)*loadL); for( zend_hash_internal_pointer_reset_ex(loadH, &p); zend_hash_get_current_data_ex(loadH, (void**) &retP, &p) == SUCCESS; zend_hash_move_forward_ex(loadH, &p)) { if(Z_TYPE_PP(retP) != IS_STRING) DBOBJ_ERROR_CRIT("zLoad2Load: an element of load array is not string"); //get basicPropConf from name and store to next pos in return array *ret = (basicPropConfig)classConfig_get_objPropConfig_handle_error(classConf, Z_STRINGLU_PP(retP)+1 TSRMLS_CC); //TODO handle complexProps (load all it's sources) assert((*ret)->Class == OBJPROP_BASIC); ret++; } return loadL; }//}}} //}}}<> //{{{<> //{{{ //{{{dbProp_freeer //static void dbProp_freeer(void *ptr) { static void dbProp_freeer(dbProp *ptr) { dbProp dp = *ptr; CALM(dp->config->dbType, dbVal_dtor, dp->value); efree(dp); }//}}} //{{{zPropCache_freeer static void zPropCache_freeer(zval **ptr) { zval *v = *ptr; zval_ptr_dtor(&v); }//}}} //}}} //{{{ //{{{ALLOC_INIT_DBOBJ #define ALLOC_INIT_DBOBJ(o) {o = emalloc(sizeof(*o));\ o->overloadedRecursionCounter = 0;\ o->lConf = lConf;\ zend_hash_init(&o->dbProps, 8, NULL, (dtor_func_t)dbProp_freeer, 0);\ zend_hash_init(&o->zPropCache, 8, NULL, (dtor_func_t)zPropCache_freeer, 0);\ o->changedDbPropCount = 0;\ o->PKs = emalloc (sizeof(*o->PKs) * lConf->cConf->PKsL);\ o->PKsL = -1;\ o->desired_dbStatus = DBSTATUS_IN_DATABASE;} //}}} //{{{dbobj_allocate_and_init DBOBJ_API dbobj dbobj_allocate_and_init(LocalClassConfig lConf TSRMLS_DC) { dbobj o; ALLOC_INIT_DBOBJ(o); return o; }//}}} //{{{dbobj_deallocate DBOBJ_API void dbobj_deallocate(dbobj o) { zend_hash_destroy(&o->dbProps); zend_hash_destroy(&o->zPropCache); if(o->PKs) efree(o->PKs); efree(o); }//}}} //}}} //{{{ //{{{dbobj_register_in_objectStore static zend_object_handle dbobj_register_in_objectStore(dbobj o TSRMLS_DC) { return zend_objects_store_put(o, (zend_objects_store_dtor_t)dbobj_destroy_object, NULL, dbobj_copy TSRMLS_CC); }//}}} //{{{dbobj_register_in_objCache static void dbobj_register_in_objCache(dbobj o, uidT uid TSRMLS_DC) { HashTable *objCacheH = &DBOBJ_G(objCache); assert(uid); /* * this is an ugly hack needed by zend_hash * on destruction it thinks that every 4 byte data is pointer, * and tries to free it */ char tmp[sizeof(void*)+1]; memcpy(tmp, &o, sizeof(&o)); zend_hash_add(objCacheH, (char*)uid, UID_GETLEN(uid), tmp, sizeof(tmp), NULL); }//}}} //{{{dbobj_unRegister_in_objCache static void dbobj_unRegister_in_objCache(dbobj o, uidT uid TSRMLS_DC) { HashTable *objCacheH = &DBOBJ_G(objCache); bool uid_was_passed; if(uid != NULL) { uid_was_passed = 1; } else { uid = dbobj_get_UID(o TSRMLS_CC); uid_was_passed = 0; } zend_hash_del(objCacheH, (char*)uid, UID_GETLEN(uid)); if(!uid_was_passed && uid) efree(uid); }//}}} //{{{dbobj_reRegister_in_objCache static void dbobj_reRegister_in_objCache(dbobj o, uidT old_uid TSRMLS_DC) { HashTable *objCacheH = &DBOBJ_G(objCache); uidT new_uid = dbobj_get_UID(o TSRMLS_CC); if(old_uid) zend_hash_del(objCacheH, (char*)old_uid, UID_GETLEN(old_uid)); dbobj_register_in_objCache(o, new_uid TSRMLS_CC); efree(new_uid); }//}}} //{{{dbobj_register DBOBJ_API zend_object_handle dbobj_register(dbobj o, uidT uid TSRMLS_DC) { bool uid_was_passed; zend_object_handle handle; if(uid != NULL) { uid_was_passed = 1; } else { uid = dbobj_get_UID(o TSRMLS_CC); uid_was_passed = 0; } //register object handle = dbobj_register_in_objectStore(o TSRMLS_CC); if(uid) dbobj_register_in_objCache(o, uid TSRMLS_CC); if(!uid_was_passed && uid) efree(uid); return handle; }//}}} //{{{dbobj_lookup_in_cache DBOBJ_API dbobj dbobj_lookup_in_cache(uidT uid TSRMLS_DC) { HashTable *objCacheH = &DBOBJ_G(objCache); dbobj *retP; if(zend_hash_find(objCacheH, (char*)uid, UID_GETLEN(uid), (void**)&retP) == SUCCESS) { dbobj o = *retP; if(!o->handle) { o->handle = dbobj_register_in_objectStore(o TSRMLS_CC); } dbobj_add_ref(o TSRMLS_CC); return o; } else { return NULL; } }//}}} //}}} //{{{ /* {{{dbobj_create * * @desc for creating new record */ DBOBJ_API dbobj dbobj_create(LocalClassConfig lConf TSRMLS_DC) { dbobj o; classConfig cConf = lConf->cConf; ALLOC_INIT_DBOBJ(o); o->dbStatus = DBSTATUS_IN_MEMORY; o->desired_dbStatus = DBSTATUS_IN_DATABASE; if(!cConf->autoID) { //no autoID o->changedDbPropCount = 0; o->PKsL = 0; o->handle = dbobj_register_in_objectStore(o TSRMLS_CC); //object doesn't have UID and can't be registered in objCache while it doesn't have PKs return o; } else { //autoID DBConnection conn = lConf->conn; uint id; o->changedDbPropCount = 1; //the one that 'changed' is the PK o->PKsL = 1; if(conn->vt->getNewID) { id = CALM(conn, getNewID, cConf TSRMLS_CC); } else { //we can't prefetch the autoID for the record //FIXME what sould we do now?? assert(0); } //store this PK into dbProps { dbProp dbp; dbp = o->PKs[0] = emalloc(sizeof(*dbp)); dbp->changed = 1; dbp->config = cConf->PKs[0]; dbp->value = CALM(dbp->config->dbType, raw2dbVal, &id); zend_hash_add(&o->dbProps, cConf->PKs[0]->name, cConf->PKs[0]->nameL, &dbp, sizeof(&dbp), NULL); } //register object o->handle = dbobj_register(o, NULL TSRMLS_CC); return o; } }//}}} /*{{{dbobj_findOne * * @desc load existring record (or fill in a record with specific PKs) if it is not in the cache * @param PKs ordered list of PKs, as in classConfig * this function takes care of destorying the dbVals in PKs array */ DBOBJ_API dbobj dbobj_findOne(LocalClassConfig lConf, dbVal PKs[], basicPropConfig load[], uint loadL TSRMLS_DC) { uint PKsL; uidT uid; dbobj o; classConfig cConf = lConf->cConf; assert(PKs); //PKs must be given, for new record creation dbobj_create should be called PKsL = cConf->PKsL; uid = create_UID_from_dbValPKs(cConf, PKs, cConf->PKsL); //see if we can find the object in the cache (to ensure there is only one object for a record) { dbobj o = dbobj_lookup_in_cache(uid TSRMLS_CC); if(o) { uint i; for(i = 0; i < cConf->PKsL; i++) { CALM(cConf->PKs[i]->dbType, dbVal_dtor, PKs[i]); } efree(uid); return o; } } //if not in cache create new object ALLOC_INIT_DBOBJ(o); o->dbStatus = DBSTATUS_IN_DATABASE; o->desired_dbStatus = DBSTATUS_IN_DATABASE; //store PKs as dbprops { dbProp* PKProps = o->PKs; uint i; basicPropConfig* currPKsConfPtr = cConf->PKs; o->PKsL = PKsL; for(i = 0; i < PKsL; i++) { char *dbPropName; uint dbPropNameL; dbProp dbp = PKProps[i] = emalloc(sizeof(*dbp)); dbp->changed = 0; dbp->config = *currPKsConfPtr; dbp->value = PKs[i]; //inset into dbProps dbPropName = (*currPKsConfPtr)->name; dbPropNameL = (*currPKsConfPtr)->nameL; zend_hash_add(&o->dbProps, dbPropName, dbPropNameL, &dbp, sizeof(&dbp), NULL); currPKsConfPtr++; } } if(!load) { load = cConf->defaultLoad; loadL = cConf->defaultLoadL; } if(!dbobj_dbPropsLoad(o, load, loadL TSRMLS_CC)) { efree(uid); dbobj_deallocate(o); return NULL; } //register object o->handle = dbobj_register(o, uid TSRMLS_CC); efree(uid); return o; }//}}} /* {{{dbobj_findOne_by_conditions */ DBOBJ_API dbobj dbobj_findOne_by_conditions(LocalClassConfig lConf, dbCondition *conditions, uint conditionsL, basicPropConfig load[], uint loadL TSRMLS_DC) { classConfig cConf = lConf->cConf; dbVal *PKs = do_alloca(cConf->PKsL * sizeof(*PKs)); dbobj o; {uint i; for(i=0; i < conditionsL; i++) { if(conditions[i].config->PKIndex != PKINDEX_NOTPK) { uint index = conditions[i].config->PKIndex; PKs[index] = conditions[i].value; } }} o = dbobj_findOne(lConf, PKs, load, loadL TSRMLS_CC); free_alloca(PKs); return o; }//}}} /*{{{dbobj_dbobj_from_UID */ DBOBJ_API dbobj dbobj_dbobj_from_UID(uidT uid, basicPropConfig load[], uint loadL TSRMLS_DC) { uint classNameL = uid->classNameL; char *className = uid->data; char *dataPtr = uid->data + classNameL + sizeof(""); LocalClassConfig lConf = localClassConfig_get(STRINGLU(className), 0 TSRMLS_CC); classConfig cConf = lConf->cConf; uint PKsL = cConf->PKsL; dbVal *PKs = emalloc(PKsL*sizeof(*PKs)); dbobj o; int i; for(i=0; i < PKsL; i++) { uint dataL = *((uint*)dataPtr); dataPtr += sizeof(uint); PKs[i] = CALM(cConf->PKs[i]->dbType, unserialize, dataPtr, dataL); //PKs[i] = dbVal_unserialize(dataPtr, dataL, cConf->PKs[i]->type); dataPtr += dataL; } # if DBOBJ_DEBUG if((char*)dataPtr != (char*)uid + uid->uidL) { DBOBJ_ERROR_CRIT("dbobj_dbobj_from_UID: data pointer after read does not match expected end of uid. dataPtr:%p, uid+uidL:%p, uidL:%d", dataPtr, (char*)uid+uid->uidL, uid->uidL); } # endif o = dbobj_findOne(lConf, PKs, load, loadL TSRMLS_CC); efree(PKs); return o; }//}}} //}}} //{{{ //{{{dbobj_add_ref DBOBJ_API void dbobj_add_ref(dbobj o TSRMLS_DC) { #if PHP_MAJOR_VERSION > 5 || PHP_MINOR_VERSION >= 2 //from PHP 5.2 zend_objects_store_add_ref_by_handle(o->handle TSRMLS_CC); #else //before PHP 5.2 EG(objects_store).object_buckets[o->handle].bucket.obj.refcount++; #endif }//}}} //{{{dbobj_del_ref DBOBJ_API void dbobj_del_ref(dbobj o TSRMLS_DC) { #if PHP_MAJOR_VERSION > 5 || PHP_MINOR_VERSION >= 2 //from PHP 5.2 zend_objects_store_del_ref_by_handle(o->handle TSRMLS_CC); #else //before PHP 5.2 if(EG(objects_store).object_buckets[o->handle].bucket.obj.refcount > 1) { EG(objects_store).object_buckets[o->handle].bucket.obj.refcount--; } else { zval zobject; INIT_ZVAL(zobject); Z_TYPE(zobject) = IS_OBJECT; Z_OBJ_HANDLE(zobject) = o->handle; Z_OBJ_HT(zobject) = &dbobj_object_handlers; zend_objects_store_del_ref(&zobject TSRMLS_CC); } #endif }//}}} //}}} //{{{dbobj_get_UID DBOBJ_API uidT dbobj_get_UID(dbobj o TSRMLS_DC) { if(o->PKsL != o->lConf->cConf->PKsL) { return NULL; } else return create_UID_from_dbPropPKs(o->lConf->cConf, o->PKs, o->PKsL); }//}}} //{{{dbobj_delete static void dbobj_delete(dbobj o TSRMLS_DC) { LocalClassConfig lConf = o->lConf; classConfig cConf = lConf->cConf; uint PKsL = o->PKsL; dbVal* PKs = do_alloca(PKsL * sizeof(*PKs)); assert(cConf->PKsL == o->PKsL); {uint i; for(i = 0; i < PKsL; i++) { PKs[i] = o->PKs[i]->value; } } CALM(lConf->conn, deleteRow, cConf, PKs, PKsL TSRMLS_CC); free_alloca(PKs); o->dbStatus = DBSTATUS_IN_MEMORY; }//}}} //{{{dbobj_insert static void dbobj_insert(dbobj o TSRMLS_DC) { LocalClassConfig lConf = o->lConf; classConfig cConf = lConf->cConf; uint savePropsL = o->changedDbPropCount; basicPropConfig* savePropConfs = do_alloca(savePropsL * sizeof(savePropConfs)); dbVal* savePropVals = do_alloca(savePropsL * sizeof(*savePropVals)); if(o->changedDbPropCount == 0) { DBOBJ_WARNING("dbobj_insert: Can't insert record with no fields!"); } assert(o->PKsL == cConf->PKsL); //fill saveprops and savePropConfigs array { HashTable *dbPropsH = &o->dbProps; HashPosition p; dbProp *retP; uint i = 0; //iterate through all the object's dbProps for( zend_hash_internal_pointer_reset_ex(dbPropsH, &p); zend_hash_get_current_data_ex(dbPropsH, (void**) &retP, &p) == SUCCESS; zend_hash_move_forward_ex(dbPropsH, &p)) { if((*retP)->changed) { savePropVals[i] = (*retP)->value; savePropConfs[i] = (*retP)->config; i++; } else { DBOBJ_WARNING("dbobj_save: found dbProp not to be saved (class: %s, dbProp:%s)", cConf->className, (*retP)->config->name); } } assert(i == savePropsL); } CALM(lConf->conn, insertRow, cConf, savePropConfs, savePropVals, savePropsL TSRMLS_CC); free_alloca(savePropConfs); free_alloca(savePropVals); o->dbStatus = DBSTATUS_IN_DATABASE; o->changedDbPropCount = 0; }//}}} //{{{dbobj_update static void dbobj_update(dbobj o TSRMLS_DC) { LocalClassConfig lConf = o->lConf; classConfig cConf = lConf->cConf; uint savePropsL = o->changedDbPropCount; basicPropConfig* savePropConfs = do_alloca(savePropsL * sizeof(savePropConfs)); dbVal* savePropVals = do_alloca(savePropsL * sizeof(*savePropVals)); uint PKsL = cConf->PKsL; dbVal* PKs = do_alloca(PKsL * sizeof(*PKs)); //check if there is anything to change if(!o->changedDbPropCount) return; assert(o->PKsL == cConf->PKsL); //fill savePropVals[] and savePropConfs[] //iterate through all the object's dbProps { HashTable *dbPropsH = &o->dbProps; HashPosition p; dbProp *retP; uint i = 0; for(zend_hash_internal_pointer_reset_ex(dbPropsH, &p); zend_hash_get_current_data_ex(dbPropsH, (void**) &retP, &p) == SUCCESS; zend_hash_move_forward_ex(dbPropsH, &p)) { if((*retP)->changed) { savePropVals[i] = (*retP)->value; savePropConfs[i] = (*retP)->config; i++; (*retP)->changed = 0; } } assert(o->PKsL == cConf->PKsL); } //fill dbVal PKs[] array {uint i; for(i = 0; i < PKsL; i++) { PKs[i] = o->PKs[i]->value; } } CALM(lConf->conn, updateRow, cConf, PKs, savePropConfs, savePropVals, savePropsL TSRMLS_CC); //free memory free_alloca(savePropConfs); free_alloca(savePropVals); free_alloca(PKs); o->changedDbPropCount = 0; }//}}} //{{{dbobj_save DBOBJ_API void dbobj_save(dbobj o TSRMLS_DC) { if(o->PKsL != o->lConf->cConf->PKsL) { if(o->desired_dbStatus == DBSTATUS_IN_DATABASE) DBOBJ_WARNING("I can't save an incomplete object!"); return; } switch (o->dbStatus) { case DBSTATUS_IN_DATABASE: switch(o->desired_dbStatus) { case DBSTATUS_IN_DATABASE: dbobj_update(o TSRMLS_CC); return; case DBSTATUS_IN_MEMORY: dbobj_delete(o TSRMLS_CC); return; } case DBSTATUS_IN_MEMORY: switch(o->desired_dbStatus) { case DBSTATUS_IN_DATABASE: dbobj_insert(o TSRMLS_CC); return; case DBSTATUS_IN_MEMORY: return; } } assert(0); }//}}} /* {{{dbobj_destroy * * call save(), free memory */ DBOBJ_API void dbobj_destroy(dbobj o TSRMLS_DC) { dbobj_save(o TSRMLS_CC); dbobj_deallocate(o); }//}}} //{{{dbobj_discard_changes DBOBJ_API void dbobj_discard_changes(dbobj o TSRMLS_DC) { /* * FIXME megirni */ }//}}} /*{{{dbobj_copyForInsert * * copies all data to the parameter except for the PKs, sets it to be inserted on destruction */ DBOBJ_API void dbobj_copyForInsert(dbobj o, dbobj copy TSRMLS_DC) { //TODO write DBOBJ_ERROR("dbobj_copyForInsert UNIMPLEMENTED!"); }//}}} //{{{dbobj_basicVal_get DBOBJ_API basicVal dbobj_basicVal_get(dbobj o, basicPropConfig basicPropConf TSRMLS_DC) { basicVal ret; dbProp dp; assert(basicPropConf->Class == OBJPROP_BASIC); dp = dbobj_dbProp_get(o,basicPropConf TSRMLS_CC); ret = CALM(basicPropConf->dbType,dbVal2basicVal,dp->value); return ret; }//}}} //{{{dbobj_complexVal_get DBOBJ_API complexVal dbobj_complexVal_get(dbobj o, complexPropConfig complexPropConf TSRMLS_DC) { uint sourcesL; basicVal *basicVals; complexVal ret; assert(complexPropConf->Class == OBJPROP_COMPLEX); sourcesL = complexPropConf->sourcesL; basicVals = emalloc(sourcesL * sizeof(*basicVals)); uint i; for(i = 0; i < sourcesL; i++) { basicVals[i] = dbobj_basicVal_get(o,complexPropConf->sources[i] TSRMLS_CC); //TODO this case shouldn't be handled only with an assertation assert(basicVals[i]); } ret = CALM(complexPropConf->type, basicVals2complexVal, basicVals TSRMLS_CC); for(i = 0; i < sourcesL; i++) { CALM(complexPropConf->sources[i]->basicType, objVal_dtor, basicVals[i] TSRMLS_CC); } efree(basicVals); return ret; }//}}} //{{{dbobj_objVal_get DBOBJ_API objVal dbobj_objVal_get(dbobj o, objPropConfig objPropConf TSRMLS_DC) { switch(objPropConf->Class) { case OBJPROP_BASIC: { return dbobj_basicVal_get(o, (basicPropConfig)objPropConf TSRMLS_CC); } case OBJPROP_COMPLEX: { return dbobj_complexVal_get(o, (complexPropConfig)objPropConf TSRMLS_CC); } } assert(0); return NULL; }//}}} //{{{dbobj_basicProp_set static void dbobj_basicProp_set(dbobj o, basicPropConfig basicPropConf, basicVal bval TSRMLS_DC) { dbVal dval; assert(basicPropConf->Class == OBJPROP_BASIC); dval = CALM(basicPropConf->dbType, basicVal2dbVal, bval); dbobj_dbProp_set(o, basicPropConf, dval TSRMLS_CC); }//}}} //{{{dbobj_complexProp_set static void dbobj_complexProp_set(dbobj o, complexPropConfig complexPropConf, complexVal cval TSRMLS_DC) { basicVal* bvals; uint i; bvals = CALM(complexPropConf->type, complexVal2basicVals, cval TSRMLS_CC); for(i=0; i < complexPropConf->sourcesL; i++) { dbobj_basicProp_set(o, complexPropConf->sources[i], bvals[i] TSRMLS_CC); } efree(bvals); }//}}} //{{{dbobj_objProp_set DBOBJ_API void dbobj_objProp_set(dbobj o, objPropConfig objPropConf, objVal val TSRMLS_DC) { switch(objPropConf->Class) { case OBJPROP_BASIC: return dbobj_basicProp_set(o, (basicPropConfig)objPropConf, (basicVal)val TSRMLS_CC); case OBJPROP_COMPLEX: return dbobj_complexProp_set(o, (complexPropConfig)objPropConf, (complexVal)val TSRMLS_CC); } assert(0); }//}}} //{{{dbobj_objPropRevert DBOBJ_API void dbobj_objPropRevert(dbobj o, objPropConfig objProp TSRMLS_DC) { /* * FIXME do the implementation */ }//}}} //{{{dbobj_basicProp_is_valid static bool dbobj_basicProp_is_valid(dbobj o, basicPropConfig basicPropConf TSRMLS_DC) { return (dbobj_dbProp_get(o, basicPropConf TSRMLS_CC) ? 1 : 0 ); }//}}} //{{{dbobj_complexProp_is_valid static bool dbobj_complexProp_is_valid(dbobj o, complexPropConfig complexPropConf TSRMLS_DC) { uint i; for(i = 0; i < complexPropConf->sourcesL; i++) { if( ! dbobj_basicProp_is_valid(o, complexPropConf->sources[i] TSRMLS_CC) ) return 0; } return 1; }//}}} /* {{{ dbobj_objProp_is_valid * * gets called by "isset($o->name)" */ DBOBJ_API bool dbobj_objProp_is_valid(dbobj o, objPropConfig objPropConf TSRMLS_DC) { switch(objPropConf->Class) { case OBJPROP_BASIC: return dbobj_basicProp_is_valid(o, (basicPropConfig)objPropConf TSRMLS_CC); case OBJPROP_COMPLEX: return dbobj_complexProp_is_valid(o, (complexPropConfig)objPropConf TSRMLS_CC); } assert(0); return 0; }//}}} //{{{dbobj_dbProp_get DBOBJ_API dbProp dbobj_dbProp_get(dbobj o, basicPropConfig conf TSRMLS_DC) { dbProp *retP; if(zend_hash_find(&o->dbProps, conf->name, conf->nameL, (void**)&retP) == SUCCESS) { return *retP; } else { if(o->dbStatus == DBSTATUS_IN_MEMORY) { return NULL; } else { //DBSTATUS_IN_DATABASE if(!dbobj_dbPropsLoad(o, &conf, 1 TSRMLS_CC)) { return NULL; } else { int tmp = zend_hash_find(&o->dbProps, conf->name, conf->nameL, (void**)&retP); assert(tmp == SUCCESS); return *retP; } } } //assert(0);return NULL; }//}}} //{{{dbobj_dbPropsLoad_default static dbProp dbobj_dbPropsLoad_default(dbobj o, basicPropConfig basicPropConf TSRMLS_DC) { HashTable *dbPropsH = &o->dbProps; char *Key; uint KeyL; dbProp p; #if DBOBJ_DEBUG if(is_dbType_serial(basicPropConf->dbType)) DBOBJ_ERROR_CRIT("dbobj trying to defaultload dbprop of type SERIAL"); #endif Key = basicPropConf->name; KeyL = basicPropConf->nameL; p = emalloc(sizeof(*p)); p->config = basicPropConf; p->changed = 0; p->value = CALM(basicPropConf->dbType, null2dbVal); //p->value = null2dbVal(basicPropConf->type); zend_hash_add(dbPropsH, Key, KeyL, &p, sizeof(&p), NULL); return p; }//}}} /* {{{dbobj_dbProp_set * this function takes care of newVal's destructon */ DBOBJ_API void dbobj_dbProp_set(dbobj o, basicPropConfig conf, dbVal newVal TSRMLS_DC) { uidT old_uid = NULL; dbProp p = dbobj_dbProp_get(o, conf TSRMLS_CC); bool isPK = (conf->PKIndex != PKINDEX_NOTPK); if(!p || CALM(conf->dbType, compare, p->value, newVal)) { //ha NULL vagy kulonbozoek if(isPK && o->PKsL == o->lConf->cConf->PKsL) { //changing a PK of a complete object old_uid = dbobj_get_UID(o TSRMLS_CC); } if(!p) { //creating a new dbProp p = dbobj_dbPropsLoad_default(o, conf TSRMLS_CC); if(isPK) { //the new dbProp is a PK o->PKs[conf->PKIndex] = p; o->PKsL++; } } if(!p->changed) o->changedDbPropCount++; p->changed = 1; CALM(conf->dbType, dbVal_dtor, p->value); p->value = newVal; if(isPK && o->PKsL == o->lConf->cConf->PKsL) { //changing a PK and the object is compete by now dbobj_reRegister_in_objCache(o, old_uid TSRMLS_CC); } } else { CALM(conf->dbType, dbVal_dtor, newVal); } }//}}} //{{{dbobj_dbPropsLoad DBOBJ_API bool dbobj_dbPropsLoad(dbobj o, basicPropConfig *load, uint loadL TSRMLS_DC) { LocalClassConfig lConf = o->lConf; classConfig cConf = lConf->cConf; int PKsL = cConf->PKsL; dbVal* PKs = do_alloca(PKsL * sizeof(*PKs)); dbVal* loadedValues; assert(o->PKsL == cConf->PKsL); if(!loadL) return 1; //nothing to load assert(o->dbStatus == DBSTATUS_IN_DATABASE); //fill dbVal PKs[] array {uint i; for(i = 0; i < PKsL; i++) { PKs[i] = o->PKs[i]->value; } } //we have to free the return value loadedValues = CALM(lConf->conn, getRow, cConf, PKs, load, loadL TSRMLS_CC); free_alloca(PKs); if(!loadedValues) { //row was not found return 0; } //process result { HashTable *dbPropsH = &o->dbProps; uint i; for(i = 0; i < loadL; i++) { char *Key = load[i]->name; uint KeyL = load[i]->nameL; dbProp p = emalloc(sizeof(*p)); p->config = load[i]; p->changed = 0; p->value = loadedValues[i]; zend_hash_add(dbPropsH, Key, KeyL, &p, sizeof(&p), NULL); }} efree(loadedValues); return 1; }//}}} //}}}<> //{{{<> //{{{ //{{{dbobjVerifyPropReadAccess #define dbobjVerifyPropReadAccess(...) \ dbobjVerifyPropAccess('r', __VA_ARGS__) //}}} //{{{ dbobjVerifyPropWriteAccess #define dbobjVerifyPropWriteAccess(...) \ dbobjVerifyPropAccess('w', __VA_ARGS__) ///}}} //{{{dbobjVerifyPropAccess static bool dbobjVerifyPropAccess(char type, zval *Zobject, classConfig cConf, objPropConfig objPropConf TSRMLS_DC) { enum accessT access; switch (type) { case 'r': access = objPropConf->readAccess; break; case 'w': access = objPropConf->writeAccess; break; default: assert(0); } switch (access) { case DBOBJ_ACC_PUBLIC: return 1; case DBOBJ_ACC_PROTECTED: { zend_class_entry *objCE = zend_get_class_entry(Zobject TSRMLS_CC); zend_class_entry *scope = EG(scope); while (scope) { if (scope==objCE) { return 1; } scope = scope->parent; } return 0; } case DBOBJ_ACC_PRIVATE: { zend_class_entry *objCE = zend_get_class_entry(Zobject TSRMLS_CC); zend_class_entry *scope = EG(scope); if (objCE==scope && scope) { return 1; } else { return 0; } } } //should never get here assert(0); return 0;//to avoid warning... }//}}} //}}} //{{{dbobj_zObjProp_get DBOBJ_API zval * dbobj_zObjProp_get(zval *zObject, STRINGLD(propName) TSRMLS_DC) { dbobj o = ZDTHIS; LocalClassConfig lConf = o->lConf; classConfig cConf = lConf->cConf; objPropConfig objPropConf; objVal ov; zval *ret; objPropConf = classConfig_get_objPropConfig_handle_error(cConf, STRINGLU(propName) TSRMLS_CC); if(! dbobjVerifyPropReadAccess(zObject, cConf, objPropConf TSRMLS_CC)) DBOBJ_ERROR("dbobj::__get called from unauthorised context. (%s.%s) was requested", cConf->className, propName); ov = dbobj_objVal_get(ZDTHIS, objPropConf TSRMLS_CC); ret = CALM(objPropConf->type, objVal2zVal, ov TSRMLS_CC); CALM(objPropConf->type, objVal_dtor, ov TSRMLS_CC); return ret; }//}}} //{{{dbobj_zObjProp_set DBOBJ_API void dbobj_zObjProp_set(zval *zObject, STRINGLD(propName), zval *value TSRMLS_DC) { LocalClassConfig lConf = ZDTHIS->lConf; classConfig cConf = lConf->cConf; objPropConfig objPropConf = classConfig_get_objPropConfig_handle_error(cConf, STRINGLU(propName) TSRMLS_CC); objVal ov; if(! dbobjVerifyPropWriteAccess(zObject, cConf, objPropConf TSRMLS_CC)) DBOBJ_ERROR("dbobj::__set called from unauthorised context. (%s.%s) was requested", cConf->className, propName); ov = CALM(objPropConf->type, zVal2objVal, value TSRMLS_CC); dbobj_objProp_set(ZDTHIS, objPropConf, ov TSRMLS_CC); CALM(objPropConf->type, objVal_dtor, ov TSRMLS_CC); }//}}} //{{{dbobj_ZObjPropRevert DBOBJ_API void dbobj_ZObjPropRevert(zval *zObject, STRINGLD(propName) TSRMLS_DC) { LocalClassConfig lConf = ZDTHIS->lConf; classConfig cConf = lConf->cConf; objPropConfig objPropConf = classConfig_get_objPropConfig_handle_error(cConf, STRINGLU(propName) TSRMLS_CC); if(! dbobjVerifyPropWriteAccess(zObject, cConf, objPropConf TSRMLS_CC)) DBOBJ_ERROR("dbobj::revert called from unauthorised context. (%s.%s) was requested", cConf->className, propName); dbobj_objPropRevert(ZDTHIS, objPropConf TSRMLS_CC); }//}}} //{{{dbobj_zObjPropValid DBOBJ_API bool dbobj_zObjPropValid(zval *zObject, STRINGLD(propName) TSRMLS_DC) { dbobj o = ZDTHIS; LocalClassConfig lConf = o->lConf; classConfig cConf = lConf->cConf; objPropConfig objPropConf = classConfig_get_objPropConfig(cConf, STRINGLU(propName) TSRMLS_CC); if(objPropConf) return dbobj_objProp_is_valid(ZDTHIS, objPropConf TSRMLS_CC); else return 0; }//}}} //{{{ //{{{dbobj_serialize static int dbobj_serialize(zval *zobject, unsigned char **s, uint *sL, zend_serialize_data *data TSRMLS_DC) { dbobj o = get_this_dbobj(zobject); uidT uid = dbobj_get_UID(o TSRMLS_CC); if(!uid) DBOBJ_ERROR("can't serialize incomplete object!"); *s = (unsigned char*) uid; *sL = UID_GETLEN(uid); return SUCCESS; }//}}} //{{{dbobj_unserialize static int dbobj_unserialize(zval **zobject, zend_class_entry *ce, const unsigned char *s, zend_uint sL, zend_unserialize_data *data TSRMLS_DC) { uidT uid = (uidT)s; dbobj o = dbobj_dbobj_from_UID(uid, NULL, 0 TSRMLS_CC); Z_TYPE_PP(zobject) = IS_OBJECT; Z_OBJ_HANDLE_PP(zobject) = o->handle; Z_OBJ_HT_PP(zobject) = &dbobj_object_handlers; return SUCCESS; }//}}} //}}} //}}}<> //{{{ <> //{{{ //{{{ dbobj_z_add_ref DBOBJ_API void dbobj_z_add_ref(zval *zObject TSRMLS_DC) { zend_objects_store_add_ref(zObject TSRMLS_CC); }//}}} //{{{dbobj_z_del_ref DBOBJ_API void dbobj_z_del_ref(zval *zObject TSRMLS_DC) { zend_objects_store_del_ref(zObject TSRMLS_CC); }//}}} //}}} //{{{dbobj_z_clone DBOBJ_API zend_object_value dbobj_z_clone(zval *object TSRMLS_DC) { //TODO write function DBOBJ_ERROR("cloning dbobj object UNIMPLEMENTED"); assert(0); //unimplemented }//}}} //{{{ //{{{dbobj_read_property DBOBJ_API zval * dbobj_read_property(zval *zObject, zval *member, int type TSRMLS_DC) { switch(member->type) { case IS_STRING: return dbobj_zObjProp_get(zObject, Z_STRVAL_P(member), Z_STRLEN_P(member) TSRMLS_CC); default: DBOBJ_ERROR("dbobj::read_property hibas keres tipus: %d" , member->type); return NULL; } }//}}} //{{{dbobj_write_property DBOBJ_API void dbobj_write_property(zval *zObject, zval *member, zval *value TSRMLS_DC) { switch(member->type) { case IS_STRING: dbobj_zObjProp_set(zObject, Z_STRVAL_P(member), Z_STRLEN_P(member), value TSRMLS_CC); break; default: DBOBJ_ERROR("dbobj::write_property hibas keres tipus: %d" , member->type); } }//}}} //{{{dbobj_has_property DBOBJ_API int dbobj_has_property(zval *zObject, zval *member, int has_set_exists TSRMLS_DC) { switch(member->type) { case IS_STRING: return dbobj_zObjPropValid(zObject, Z_STRVAL_P(member), Z_STRLEN_P(member) TSRMLS_CC); } DBOBJ_ERROR("dbobj::has_property hibas keres tipus: %d" , member->type); return 0; }//}}} //{{{dbobj_unset_property DBOBJ_API void dbobj_unset_property(zval *zObject, zval *member TSRMLS_DC) { switch(member->type) { case IS_STRING: dbobj_ZObjPropRevert(zObject, Z_STRVAL_P(member), Z_STRLEN_P(member) TSRMLS_CC); default: DBOBJ_ERROR("dbobj::unset_property hibas keres tipus: %d" , member->type); } }//}}} //{{{dbobj_get_properties DBOBJ_API HashTable * dbobj_get_properties(zval *zObject TSRMLS_DC) { dbobj o = ZDTHIS; return &o->zPropCache; }//}}} //}}} //{{{dbobj_get_method DBOBJ_API union _zend_function * dbobj_get_method(zval **zObjectP, char *methodName, int methodNameL TSRMLS_DC) { zend_class_entry *ce = dbobj_get_class(*zObjectP TSRMLS_CC); return dbobj_general_get_method(ce, methodName, methodNameL TSRMLS_CC); }//}}} //{{{dbobj_call_method DBOBJ_API int dbobj_call_method(char *method, INTERNAL_FUNCTION_PARAMETERS) { /* * TODO todo ha megirom, figyelni kell a read/write access -re! * hogy ne lehessen automata get/set fv-ellek megkerulni a read_access/write_access -t */ DBOBJ_ERROR("dbobj::call_method unimplemented\n"); return FAILURE; }//}}} /* {{{dbobj_get_constructor * * based on zend_std_get_constructor */ DBOBJ_API union _zend_function * dbobj_get_constructor(zval *zObject TSRMLS_DC) { dbobj o = ZDTHIS; LocalClassConfig lConf = o->lConf; classConfig cConf = lConf->cConf; zend_class_entry *ce; zend_class_entry **ceP; zend_function *constructor; if(zend_lookup_class(cConf->className, cConf->classNameL, &ceP TSRMLS_CC) != SUCCESS) { DBOBJ_ERROR("nem letezo osztaly konstruktoranak keresese: %s",cConf->className); } ce = *ceP; constructor = ce->constructor; if (constructor) { if (constructor->op_array.fn_flags & ZEND_ACC_PUBLIC) { /* No further checks necessary */ } else if (constructor->op_array.fn_flags & ZEND_ACC_PRIVATE) { /* Ensure that if we're calling a private function, we're allowed to do so. */ if (ce != EG(scope)) { if (EG(scope)) { zend_error(E_ERROR, "Call to private %s::%s() from context '%s'", constructor->common.scope->name, constructor->common.function_name, EG(scope)->name); } else { zend_error(E_ERROR, "Call to private %s::%s() from invalid context", constructor->common.scope->name, constructor->common.function_name); } } } else if ((constructor->common.fn_flags & ZEND_ACC_PROTECTED)) { /* Ensure that if we're calling a protected function, we're allowed to do so. */ if (!zend_check_protected(constructor->common.prototype ? constructor->common.prototype->common.scope : constructor->common.scope, EG(scope))) { if (EG(scope)) { zend_error(E_ERROR, "Call to protected %s::%s() from context '%s'", constructor->common.scope->name, constructor->common.function_name, EG(scope)->name); } else { zend_error(E_ERROR, "Call to protected %s::%s() from invalid context", constructor->common.scope->name, constructor->common.function_name); } } } } return constructor; }//}}} //{{{dbobj_get_class DBOBJ_API zend_class_entry * dbobj_get_class(zval *zObject TSRMLS_DC) { zend_class_entry **cePP; LocalClassConfig lConf = ZDTHIS->lConf; classConfig cConf = lConf->cConf; if (zend_lookup_class(STRINGLU(cConf->className), &cePP TSRMLS_CC) == FAILURE) DBOBJ_ERROR( "dbobj_get_class: class nem letezik (%s)", cConf->className); return *cePP; }//}}} //{{{dbobj_get_className DBOBJ_API int dbobj_get_className(zval *zObject, char **className, zend_uint *classNameL, int parent TSRMLS_DC) { LocalClassConfig lConf = ZDTHIS->lConf; classConfig cConf = lConf->cConf; if(parent) { DBOBJ_ERROR("dbobj::get_className parent request unimplemented\n"); return FAILURE; } *classNameL = cConf->classNameL; *className = estrndup(cConf->className, cConf->classNameL); //=emalloc(sizeof(char) * (cConf->classNameL + 1)); //strncpy(*className, cConf->className, cConf->classNameL + 1 ); return SUCCESS; }//}}} //{{{dbobj_compare DBOBJ_API int dbobj_compare(zval *object1, zval *object2 TSRMLS_DC) { return (Z_OBJ_HANDLE_P(object1) != Z_OBJ_HANDLE_P(object2)); }//}}} //{{{dbobj_cast DBOBJ_API int dbobj_cast(zval *readObj, zval *writeObj, int type #if ! (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION == 2) , void *extra #endif TSRMLS_DC) { switch(type) { case IS_OBJECT: Z_OBJ_HANDLE_P(writeObj) = Z_OBJ_HANDLE_P(readObj); Z_OBJ_HT_P(writeObj) = &dbobj_object_handlers; break; case IS_NULL: break; case IS_BOOL: Z_LVAL_P(writeObj) = 1; break; default: return FAILURE; } return SUCCESS; }//}}} //{{{dbobj_count_elements DBOBJ_API int dbobj_count_elements(zval *zObject, long *count TSRMLS_DC) { *count = ZDTHIS->lConf->cConf->objProps.nNumOfElements; return SUCCESS; }//}}} //{{{dbobj_copy DBOBJ_API void dbobj_copy(void *object, void **object_clone TSRMLS_DC) { DBOBJ_ERROR("dobj copying unimplemented\n"); }//}}} //{{{dbobj_create_object DBOBJ_API zend_object_value dbobj_create_object(zend_class_entry *ce TSRMLS_DC) { zend_object_value retval; LocalClassConfig lConf; if(ce == dbobj_class_entry_ptr) DBOBJ_ERROR_CRIT("Cannot instantiate dbobj, it is abstract!"); lConf = localClassConfig_get(ce->name, ce->name_length, 0 TSRMLS_CC); if(!lConf) { DBOBJ_ERROR_CRIT("dbobj_create_object no class config"); return retval; } //new dbobj object { dbobj o = dbobj_create(lConf TSRMLS_CC); retval.handle = o->handle; retval.handlers = &dbobj_object_handlers; } return retval; }//}}} //{{{dbobj_destroy_object DBOBJ_API void dbobj_destroy_object(dbobj o, zend_object_handle handle TSRMLS_DC) { HashTable *garbage_list = &DBOBJ_G(garbage_list); uidT uid = dbobj_get_UID(o TSRMLS_CC); if(!uid) { //incomplete object can't be multi-referenced dbobj_destroy(o TSRMLS_CC); } else { //uid /* * store * * this is an ugly hack needed by zend_hash * on destruction it thinks that every 4 byte data is pointer, * and tries to free it */ { char tmp[sizeof(void*)+1]; memcpy(tmp, &o, sizeof(&o)); zend_hash_add(garbage_list, (char*)uid, UID_GETLEN(uid), tmp, sizeof(tmp), NULL); } /* * this function is the destructor of the object in object_store, so when * this is called, the object's handle is not valid anymore. */ o->handle = 0; efree(uid); } }//}}} //{{{dbobj_garbage_collection DBOBJ_API void dbobj_garbage_collection(TSRMLS_D) { HashTable *garbage_list = &DBOBJ_G(garbage_list); HashPosition p; dbobj *retP; for(zend_hash_internal_pointer_reset_ex(garbage_list, &p); zend_hash_get_current_data_ex(garbage_list, (void**) &retP, &p) == SUCCESS; zend_hash_move_forward_ex(garbage_list, &p)) { dbobj_unRegister_in_objCache(*retP, NULL TSRMLS_CC); dbobj_destroy(*retP TSRMLS_CC); } }//}}} //}}} <> //{{{ //{{{ proto void dbobj->save() PHP_METHOD(dbobj, save) { dbobj o = ZDGETTHIS(); dbobj_save(o TSRMLS_CC); }//}}} //{{{ proto boolean dbobj->delete_on_save ( [ bool $set_to ] ) PHP_METHOD(dbobj, delete_on_save) { zend_bool set_to_delete; dbobj o; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &set_to_delete) == FAILURE) { RETURN_NULL(); } o = ZDGETTHIS(); if(ZEND_NUM_ARGS() > 0) { if(set_to_delete) { o->desired_dbStatus = DBSTATUS_IN_MEMORY; } else { o->desired_dbStatus = DBSTATUS_IN_DATABASE; } } RETURN_BOOL(o->desired_dbStatus == DBSTATUS_IN_MEMORY); }//}}} //{{{ proto boolean dbobj->is_in_database ( ) PHP_METHOD(dbobj, is_in_database) { dbobj o = ZDGETTHIS(); RETURN_BOOL(o->dbStatus == DBSTATUS_IN_DATABASE); }//}}} //}}} //{{{ /* {{{ proto object dbobj_find ( string $class_name, array $conditions [, array $extra_sql [, array $load ]] ) * returns all matching recrods from the configued table * * @param string $class_name * @param array $conditions key-value pairs where keys are names of objprops and values that will be required to match them * @param array $sql SQL code to be inserted in query at certain points (where, orderby, limit) * @param array $load list of names of dbprops to be loaded by default * * @return dbobj if PKs were given, dbobjIterator otherwise */ PHP_FUNCTION(dbobj_find) { char *className; uint classNameL; zval *zConditions; zval *zExtraSQL = NULL; zval *zLoad = NULL; LocalClassConfig lConf; classConfig cConf; dbCondition *conditions; uint conditionsL; uint PKcount = 0; basicPropConfig *load = NULL; uint loadL = 0; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|aaa", &className, &classNameL, &zConditions, &zExtraSQL, &zLoad) == FAILURE) { RETURN_NULL(); } lConf = localClassConfig_get(className, classNameL, 0 TSRMLS_CC); cConf = lConf->cConf; //dbVal *PKs = zPKs2PKs(cConf, zPKs TSRMLS_CC); if(ZEND_NUM_ARGS() >= 2) { conditionsL = zConditions2Conditons(&conditions, cConf, zConditions TSRMLS_CC); } else { conditionsL = 0; conditions = NULL; } { bool *PKmap = ecalloc(cConf->PKsL, sizeof(bool)); uint i; for(i=0; i < conditionsL; i++) { if(conditions[i].config->PKIndex != PKINDEX_NOTPK) { uint index = conditions[i].config->PKIndex; if( PKmap[index] == 0) { PKcount ++; PKmap[index] = 1; } } } efree(PKmap); } if(zLoad) {//megvan hatarozva, mit kell betolteni loadL = zLoad2Load(&load, cConf, zLoad TSRMLS_CC); } assert(PKcount <= cConf->PKsL); if(PKcount == cConf->PKsL) {//select 0..1 record dbobj o = dbobj_findOne_by_conditions(lConf, conditions, conditionsL, load, loadL TSRMLS_CC); if(o) { Z_TYPE_P(return_value) = IS_OBJECT; Z_OBJ_HANDLE_P(return_value) = o->handle; Z_OBJ_HT_P(return_value) = &dbobj_object_handlers; } else { Z_TYPE_P(return_value) = IS_NULL; } } else { //select 0..n record dbobjIterator it = dbobjIterator_create(lConf, conditions, conditionsL, load, loadL TSRMLS_CC); if(it) { Z_TYPE_P(return_value) = IS_OBJECT; Z_OBJ_HANDLE_P(return_value) = it->handle; Z_OBJ_HT_P(return_value) = &dbobjIterator_object_handlers; } else { Z_TYPE_P(return_value) = IS_NULL; } } if(conditions) { efree(conditions); } if(load && load != cConf->defaultLoad) { efree(load); } }//}}} //}}} //{{{ dbobj_object_handlers = {...} zend_object_handlers dbobj_object_handlers = { dbobj_z_add_ref, /* add_ref */ dbobj_z_del_ref, /* del_ref */ dbobj_z_clone, /* clone_obj */ dbobj_read_property, /* read_property */ dbobj_write_property, /* write_property */ dbobj_read_property, /* read_dimension */ dbobj_write_property, /* write_dimension */ NULL, /* get_property_ptr_ptr */ NULL, /* get */ NULL, /* set */ dbobj_has_property, /* has_property */ dbobj_unset_property, /* unset_property */ dbobj_has_property, /* has_dimension */ dbobj_unset_property, /* unset_dimension */ dbobj_get_properties, /* get_properties */ dbobj_get_method, /* get_method */ dbobj_call_method, /* call_method */ dbobj_get_constructor, /* get_constructor */ dbobj_get_class, /* get_class_entry */ dbobj_get_className, /* get_class_name */ dbobj_compare, /* compare_objects */ dbobj_cast, /* cast_object */ dbobj_count_elements, /* count_elements */ }; //}}} //{{{ //{{{php_dbobj_MINIT_dbobj DBOBJ_API void php_dbobj_MINIT_dbobj(int module_number TSRMLS_DC) { zend_class_entry dbobj_class_entry; {//protection against multiple calls dl() in the same process zend_class_entry **cePP; if(EG(class_table) && zend_lookup_class("dbobj", sizeof("dbobj") - 1, &cePP TSRMLS_CC) == SUCCESS) { DBOBJ_ERROR("can't register dbobj class, it allready exists! Maybe you have tried to load dbobj with dl() ?"); return; } } INIT_CLASS_ENTRY(dbobj_class_entry, "dbobj", php_dbobj_class_functions); dbobj_class_entry.create_object = dbobj_create_object; dbobj_class_entry.serialize = dbobj_serialize; dbobj_class_entry.unserialize = dbobj_unserialize; dbobj_class_entry_ptr = zend_register_internal_class(&dbobj_class_entry TSRMLS_CC); dbobj_class_entry_ptr->create_object = dbobj_create_object; }//}}} //{{{php_dbobj_RINIT_dbobj DBOBJ_API void php_dbobj_RINIT_dbobj(TSRMLS_D) { if(zend_hash_init_ex(&DBOBJ_G(objCache), 0, NULL, void_dtor, 0, 0) == FAILURE) //void_dtor: destruct dbobjs in a different way DBOBJ_ERROR_CRIT("dbobj inicializacios hiba"); if(zend_hash_init_ex(&DBOBJ_G(garbage_list), 0, NULL, void_dtor, 0, 0) == FAILURE) //void_dtor: destruct dbobjs in a different way DBOBJ_ERROR_CRIT("dbobj inicializacios hiba"); }//}}} //{{{php_dbobj_RSHUTDOWN_dbobj DBOBJ_API void php_dbobj_RSHUTDOWN_dbobj(TSRMLS_D) { dbobj_garbage_collection(TSRMLS_C); zend_hash_destroy(&DBOBJ_G(objCache)); zend_hash_destroy(&DBOBJ_G(garbage_list)); }//}}} //}}} /* * vim600: noet sw=4 ts=4 fdm=marker * vim<600: noet sw=4 ts=4 */