@@ -5091,44 +5091,32 @@ public function createOrUpdateDocumentsWithIncrease(
50915091 /**
50925092 * Increase a document attribute by a value
50935093 *
5094- * @param string $collection
5095- * @param string $id
5096- * @param string $attribute
5097- * @param int|float $value
5098- * @param int|float|null $max
5099- * @return bool
5100- *
5094+ * @param string $collection The collection ID
5095+ * @param string $id The document ID
5096+ * @param string $attribute The attribute to increase
5097+ * @param int|float $value The value to increase the attribute by, can be a float
5098+ * @param int|float|null $max The maximum value the attribute can reach after the increase, null means no limit
5099+ * @return int The new value of the attribute after the increase
51015100 * @throws AuthorizationException
51025101 * @throws DatabaseException
5103- * @throws Exception
5102+ * @throws LimitException
5103+ * @throws NotFoundException
5104+ * @throws TypeException
5105+ * @throws \Throwable
51045106 */
5105- public function increaseDocumentAttribute (string $ collection , string $ id , string $ attribute , int |float $ value = 1 , int |float |null $ max = null ): bool
5106- {
5107+ public function increaseDocumentAttribute (
5108+ string $ collection ,
5109+ string $ id ,
5110+ string $ attribute ,
5111+ int |float $ value = 1 ,
5112+ int |float |null $ max = null
5113+ ): int |float {
51075114 if ($ value <= 0 ) { // Can be a float
51085115 throw new DatabaseException ('Value must be numeric and greater than 0 ' );
51095116 }
51105117
5111- $ validator = new Authorization (self ::PERMISSION_UPDATE );
5112-
5113- /* @var $document Document */
5114- $ document = Authorization::skip (fn () => $ this ->silent (fn () => $ this ->getDocument ($ collection , $ id ))); // Skip ensures user does not need read permission for this
5115-
5116- if ($ document ->isEmpty ()) {
5117- return false ;
5118- }
5119-
51205118 $ collection = $ this ->silent (fn () => $ this ->getCollection ($ collection ));
51215119
5122- if ($ collection ->getId () !== self ::METADATA ) {
5123- $ documentSecurity = $ collection ->getAttribute ('documentSecurity ' , false );
5124- if (!$ validator ->isValid ([
5125- ...$ collection ->getUpdate (),
5126- ...($ documentSecurity ? $ document ->getUpdate () : [])
5127- ])) {
5128- throw new AuthorizationException ($ validator ->getDescription ());
5129- }
5130- }
5131-
51325120 $ attr = \array_filter ($ collection ->getAttribute ('attributes ' , []), function ($ a ) use ($ attribute ) {
51335121 return $ a ['$id ' ] === $ attribute ;
51345122 });
@@ -5137,46 +5125,63 @@ public function increaseDocumentAttribute(string $collection, string $id, string
51375125 throw new NotFoundException ('Attribute not found ' );
51385126 }
51395127
5140- $ whiteList = [self ::VAR_INTEGER , self ::VAR_FLOAT ];
5128+ $ whiteList = [
5129+ self ::VAR_INTEGER ,
5130+ self ::VAR_FLOAT
5131+ ];
51415132
5142- /**
5143- * @var Document $attr
5144- */
5133+ /** @var Document $attr */
51455134 $ attr = \end ($ attr );
51465135 if (!in_array ($ attr ->getAttribute ('type ' ), $ whiteList )) {
51475136 throw new TypeException ('Attribute type must be one of: ' . implode (', ' , $ whiteList ));
51485137 }
51495138
5150- if ( $ max && ( $ document -> getAttribute ( $ attribute ) + $ value > $ max) ) {
5151- throw new LimitException ( ' Attribute value exceeds maximum limit: ' . $ max );
5152- }
5139+ $ document = $ this -> withTransaction ( function () use ( $ collection , $ id , $ attribute , $ value , $ max ) {
5140+ /* @var $document Document */
5141+ $ document = Authorization:: skip ( fn () => $ this -> silent ( fn () => $ this -> getDocument ( $ collection -> getId (), $ id , forUpdate: true ))); // Skip ensures user does not need read permission for this
51535142
5154- $ time = DateTime:: now ();
5155- $ updatedAt = $ document -> getUpdatedAt () ;
5156- $ updatedAt = ( empty ( $ updatedAt ) || ! $ this -> preserveDates ) ? $ time : $ updatedAt ;
5143+ if ( $ document -> isEmpty ()) {
5144+ return false ;
5145+ }
51575146
5158- // Check if document was updated after the request timestamp
5159- $ oldUpdatedAt = new \DateTime ($ document ->getUpdatedAt ());
5160- if (!is_null ($ this ->timestamp ) && $ oldUpdatedAt > $ this ->timestamp ) {
5161- throw new ConflictException ('Document was updated after the request timestamp ' );
5162- }
5147+ $ validator = new Authorization (self ::PERMISSION_UPDATE );
5148+
5149+ if ($ collection ->getId () !== self ::METADATA ) {
5150+ $ documentSecurity = $ collection ->getAttribute ('documentSecurity ' , false );
5151+ if (!$ validator ->isValid ([
5152+ ...$ collection ->getUpdate (),
5153+ ...($ documentSecurity ? $ document ->getUpdate () : [])
5154+ ])) {
5155+ throw new AuthorizationException ($ validator ->getDescription ());
5156+ }
5157+ }
51635158
5164- $ max = $ max ? $ max - $ value : null ;
5159+ if ($ max && ($ document ->getAttribute ($ attribute ) + $ value > $ max )) {
5160+ throw new LimitException ('Attribute value exceeds maximum limit: ' . $ max );
5161+ }
51655162
5166- $ result = $ this ->adapter ->increaseDocumentAttribute (
5167- $ collection ->getId (),
5168- $ id ,
5169- $ attribute ,
5170- $ value ,
5171- $ updatedAt ,
5172- max: $ max
5173- );
5163+ $ time = DateTime::now ();
5164+ $ updatedAt = $ document ->getUpdatedAt ();
5165+ $ updatedAt = (empty ($ updatedAt ) || !$ this ->preserveDates ) ? $ time : $ updatedAt ;
5166+ $ max = $ max ? $ max - $ value : null ;
5167+
5168+ $ this ->adapter ->increaseDocumentAttribute (
5169+ $ collection ->getId (),
5170+ $ id ,
5171+ $ attribute ,
5172+ $ value ,
5173+ $ updatedAt ,
5174+ max: $ max
5175+ );
5176+
5177+ return $ document ;
5178+ });
51745179
51755180 $ this ->purgeCachedDocument ($ collection ->getId (), $ id );
51765181
51775182 $ this ->trigger (self ::EVENT_DOCUMENT_INCREASE , $ document );
51785183
5179- return $ result ;
5184+ return $ document -> getAttribute ( $ attribute ) + $ value ;
51805185 }
51815186
51825187
@@ -5188,38 +5193,24 @@ public function increaseDocumentAttribute(string $collection, string $id, string
51885193 * @param string $attribute
51895194 * @param int|float $value
51905195 * @param int|float|null $min
5191- * @return bool
5196+ * @return int|float
51925197 *
51935198 * @throws AuthorizationException
51945199 * @throws DatabaseException
51955200 */
5196- public function decreaseDocumentAttribute (string $ collection , string $ id , string $ attribute , int |float $ value = 1 , int |float |null $ min = null ): bool
5197- {
5201+ public function decreaseDocumentAttribute (
5202+ string $ collection ,
5203+ string $ id ,
5204+ string $ attribute ,
5205+ int |float $ value = 1 ,
5206+ int |float |null $ min = null
5207+ ): int |float {
51985208 if ($ value <= 0 ) { // Can be a float
51995209 throw new DatabaseException ('Value must be numeric and greater than 0 ' );
52005210 }
52015211
5202- $ validator = new Authorization (self ::PERMISSION_UPDATE );
5203-
5204- /* @var $document Document */
5205- $ document = Authorization::skip (fn () => $ this ->silent (fn () => $ this ->getDocument ($ collection , $ id ))); // Skip ensures user does not need read permission for this
5206-
5207- if ($ document ->isEmpty ()) {
5208- return false ;
5209- }
5210-
52115212 $ collection = $ this ->silent (fn () => $ this ->getCollection ($ collection ));
52125213
5213- if ($ collection ->getId () !== self ::METADATA ) {
5214- $ documentSecurity = $ collection ->getAttribute ('documentSecurity ' , false );
5215- if (!$ validator ->isValid ([
5216- ...$ collection ->getUpdate (),
5217- ...($ documentSecurity ? $ document ->getUpdate () : [])
5218- ])) {
5219- throw new AuthorizationException ($ validator ->getDescription ());
5220- }
5221- }
5222-
52235214 $ attr = \array_filter ($ collection ->getAttribute ('attributes ' , []), function ($ a ) use ($ attribute ) {
52245215 return $ a ['$id ' ] === $ attribute ;
52255216 });
@@ -5228,7 +5219,10 @@ public function decreaseDocumentAttribute(string $collection, string $id, string
52285219 throw new NotFoundException ('Attribute not found ' );
52295220 }
52305221
5231- $ whiteList = [self ::VAR_INTEGER , self ::VAR_FLOAT ];
5222+ $ whiteList = [
5223+ self ::VAR_INTEGER ,
5224+ self ::VAR_FLOAT
5225+ ];
52325226
52335227 /**
52345228 * @var Document $attr
@@ -5238,36 +5232,52 @@ public function decreaseDocumentAttribute(string $collection, string $id, string
52385232 throw new TypeException ('Attribute type must be one of: ' . \implode (', ' , $ whiteList ));
52395233 }
52405234
5241- if ( $ min && ( $ document -> getAttribute ( $ attribute ) - $ value < $ min) ) {
5242- throw new LimitException ( ' Attribute value exceeds minimum limit: ' . $ min );
5243- }
5235+ $ document = $ this -> withTransaction ( function () use ( $ collection , $ id , $ attribute , $ value , $ min ) {
5236+ /* @var $document Document */
5237+ $ document = Authorization:: skip ( fn () => $ this -> silent ( fn () => $ this -> getDocument ( $ collection -> getId (), $ id , forUpdate: true ))); // Skip ensures user does not need read permission for this
52445238
5245- $ time = DateTime:: now ();
5246- $ updatedAt = $ document -> getUpdatedAt () ;
5247- $ updatedAt = ( empty ( $ updatedAt ) || ! $ this -> preserveDates ) ? $ time : $ updatedAt ;
5239+ if ( $ document -> isEmpty ()) {
5240+ return false ;
5241+ }
52485242
5249- // Check if document was updated after the request timestamp
5250- $ oldUpdatedAt = new \DateTime ($ document ->getUpdatedAt ());
5251- if (!is_null ($ this ->timestamp ) && $ oldUpdatedAt > $ this ->timestamp ) {
5252- throw new ConflictException ('Document was updated after the request timestamp ' );
5253- }
5243+ $ validator = new Authorization (self ::PERMISSION_UPDATE );
52545244
5255- $ min = $ min ? $ min + $ value : null ;
5245+ if ($ collection ->getId () !== self ::METADATA ) {
5246+ $ documentSecurity = $ collection ->getAttribute ('documentSecurity ' , false );
5247+ if (!$ validator ->isValid ([
5248+ ...$ collection ->getUpdate (),
5249+ ...($ documentSecurity ? $ document ->getUpdate () : [])
5250+ ])) {
5251+ throw new AuthorizationException ($ validator ->getDescription ());
5252+ }
5253+ }
52565254
5257- $ result = $ this ->adapter ->increaseDocumentAttribute (
5258- $ collection ->getId (),
5259- $ id ,
5260- $ attribute ,
5261- $ value * -1 ,
5262- $ updatedAt ,
5263- min: $ min
5264- );
5255+ if ($ min && ($ document ->getAttribute ($ attribute ) - $ value < $ min )) {
5256+ throw new LimitException ('Attribute value exceeds minimum limit: ' . $ min );
5257+ }
5258+
5259+ $ time = DateTime::now ();
5260+ $ updatedAt = $ document ->getUpdatedAt ();
5261+ $ updatedAt = (empty ($ updatedAt ) || !$ this ->preserveDates ) ? $ time : $ updatedAt ;
5262+ $ min = $ min ? $ min + $ value : null ;
5263+
5264+ $ this ->adapter ->increaseDocumentAttribute (
5265+ $ collection ->getId (),
5266+ $ id ,
5267+ $ attribute ,
5268+ $ value * -1 ,
5269+ $ updatedAt ,
5270+ min: $ min
5271+ );
5272+
5273+ return $ document ;
5274+ });
52655275
52665276 $ this ->purgeCachedDocument ($ collection ->getId (), $ id );
52675277
52685278 $ this ->trigger (self ::EVENT_DOCUMENT_DECREASE , $ document );
52695279
5270- return $ result ;
5280+ return $ document -> getAttribute ( $ attribute ) - $ value ;
52715281 }
52725282
52735283 /**
0 commit comments