@@ -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 Document
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+ ): Document {
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,66 @@ 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+ throw new NotFoundException ( ' Document not found ' );
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 );
51635148
5164- $ max = $ max ? $ max - $ value : null ;
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+ }
51655158
5166- $ result = $ this ->adapter ->increaseDocumentAttribute (
5167- $ collection ->getId (),
5168- $ id ,
5169- $ attribute ,
5170- $ value ,
5171- $ updatedAt ,
5172- max: $ max
5173- );
5159+ if ($ max && ($ document ->getAttribute ($ attribute ) + $ value > $ max )) {
5160+ throw new LimitException ('Attribute value exceeds maximum limit: ' . $ max );
5161+ }
5162+
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 ->setAttribute (
5178+ $ attribute ,
5179+ $ document ->getAttribute ($ attribute ) + $ value
5180+ );
5181+ });
51745182
51755183 $ this ->purgeCachedDocument ($ collection ->getId (), $ id );
51765184
51775185 $ this ->trigger (self ::EVENT_DOCUMENT_INCREASE , $ document );
51785186
5179- return $ result ;
5187+ return $ document ;
51805188 }
51815189
51825190
@@ -5188,38 +5196,24 @@ public function increaseDocumentAttribute(string $collection, string $id, string
51885196 * @param string $attribute
51895197 * @param int|float $value
51905198 * @param int|float|null $min
5191- * @return bool
5199+ * @return Document
51925200 *
51935201 * @throws AuthorizationException
51945202 * @throws DatabaseException
51955203 */
5196- public function decreaseDocumentAttribute (string $ collection , string $ id , string $ attribute , int |float $ value = 1 , int |float |null $ min = null ): bool
5197- {
5204+ public function decreaseDocumentAttribute (
5205+ string $ collection ,
5206+ string $ id ,
5207+ string $ attribute ,
5208+ int |float $ value = 1 ,
5209+ int |float |null $ min = null
5210+ ): Document {
51985211 if ($ value <= 0 ) { // Can be a float
51995212 throw new DatabaseException ('Value must be numeric and greater than 0 ' );
52005213 }
52015214
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-
52115215 $ collection = $ this ->silent (fn () => $ this ->getCollection ($ collection ));
52125216
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-
52235217 $ attr = \array_filter ($ collection ->getAttribute ('attributes ' , []), function ($ a ) use ($ attribute ) {
52245218 return $ a ['$id ' ] === $ attribute ;
52255219 });
@@ -5228,7 +5222,10 @@ public function decreaseDocumentAttribute(string $collection, string $id, string
52285222 throw new NotFoundException ('Attribute not found ' );
52295223 }
52305224
5231- $ whiteList = [self ::VAR_INTEGER , self ::VAR_FLOAT ];
5225+ $ whiteList = [
5226+ self ::VAR_INTEGER ,
5227+ self ::VAR_FLOAT
5228+ ];
52325229
52335230 /**
52345231 * @var Document $attr
@@ -5238,36 +5235,55 @@ public function decreaseDocumentAttribute(string $collection, string $id, string
52385235 throw new TypeException ('Attribute type must be one of: ' . \implode (', ' , $ whiteList ));
52395236 }
52405237
5241- if ( $ min && ( $ document -> getAttribute ( $ attribute ) - $ value < $ min) ) {
5242- throw new LimitException ( ' Attribute value exceeds minimum limit: ' . $ min );
5243- }
5238+ $ document = $ this -> withTransaction ( function () use ( $ collection , $ id , $ attribute , $ value , $ min ) {
5239+ /* @var $document Document */
5240+ $ document = Authorization:: skip ( fn () => $ this -> silent ( fn () => $ this -> getDocument ( $ collection -> getId (), $ id , forUpdate: true ))); // Skip ensures user does not need read permission for this
52445241
5245- $ time = DateTime:: now ();
5246- $ updatedAt = $ document -> getUpdatedAt ( );
5247- $ updatedAt = ( empty ( $ updatedAt ) || ! $ this -> preserveDates ) ? $ time : $ updatedAt ;
5242+ if ( $ document -> isEmpty ()) {
5243+ throw new NotFoundException ( ' Document not found ' );
5244+ }
52485245
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- }
5246+ $ validator = new Authorization (self ::PERMISSION_UPDATE );
52545247
5255- $ min = $ min ? $ min + $ value : null ;
5248+ if ($ collection ->getId () !== self ::METADATA ) {
5249+ $ documentSecurity = $ collection ->getAttribute ('documentSecurity ' , false );
5250+ if (!$ validator ->isValid ([
5251+ ...$ collection ->getUpdate (),
5252+ ...($ documentSecurity ? $ document ->getUpdate () : [])
5253+ ])) {
5254+ throw new AuthorizationException ($ validator ->getDescription ());
5255+ }
5256+ }
52565257
5257- $ result = $ this ->adapter ->increaseDocumentAttribute (
5258- $ collection ->getId (),
5259- $ id ,
5260- $ attribute ,
5261- $ value * -1 ,
5262- $ updatedAt ,
5263- min: $ min
5264- );
5258+ if ($ min && ($ document ->getAttribute ($ attribute ) - $ value < $ min )) {
5259+ throw new LimitException ('Attribute value exceeds minimum limit: ' . $ min );
5260+ }
5261+
5262+ $ time = DateTime::now ();
5263+ $ updatedAt = $ document ->getUpdatedAt ();
5264+ $ updatedAt = (empty ($ updatedAt ) || !$ this ->preserveDates ) ? $ time : $ updatedAt ;
5265+ $ min = $ min ? $ min + $ value : null ;
5266+
5267+ $ this ->adapter ->increaseDocumentAttribute (
5268+ $ collection ->getId (),
5269+ $ id ,
5270+ $ attribute ,
5271+ $ value * -1 ,
5272+ $ updatedAt ,
5273+ min: $ min
5274+ );
5275+
5276+ return $ document ->setAttribute (
5277+ $ attribute ,
5278+ $ document ->getAttribute ($ attribute ) - $ value
5279+ );
5280+ });
52655281
52665282 $ this ->purgeCachedDocument ($ collection ->getId (), $ id );
52675283
52685284 $ this ->trigger (self ::EVENT_DOCUMENT_DECREASE , $ document );
52695285
5270- return $ result ;
5286+ return $ document ;
52715287 }
52725288
52735289 /**
0 commit comments