97 lines
		
	
	
		
			2.6 KiB
		
	
	
	
		
			PHP
		
	
	
	
			
		
		
	
	
			97 lines
		
	
	
		
			2.6 KiB
		
	
	
	
		
			PHP
		
	
	
	
| <?php
 | |
| 
 | |
| namespace BookStack\References;
 | |
| 
 | |
| use BookStack\Entities\EntityProvider;
 | |
| use BookStack\Entities\Models\Entity;
 | |
| use Illuminate\Database\Eloquent\Collection;
 | |
| 
 | |
| class ReferenceStore
 | |
| {
 | |
|     public function __construct(
 | |
|         protected EntityProvider $entityProvider
 | |
|     ) {
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Update the outgoing references for the given entity.
 | |
|      */
 | |
|     public function updateForEntity(Entity $entity): void
 | |
|     {
 | |
|         $this->updateForEntities([$entity]);
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Update the outgoing references for all entities in the system.
 | |
|      */
 | |
|     public function updateForAll(): void
 | |
|     {
 | |
|         Reference::query()->delete();
 | |
| 
 | |
|         foreach ($this->entityProvider->all() as $entity) {
 | |
|             $entity->newQuery()->select(['id', $entity->htmlField])->chunk(100, function (Collection $entities) {
 | |
|                 $this->updateForEntities($entities->all());
 | |
|             });
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Update the outgoing references for the entities in the given array.
 | |
|      *
 | |
|      * @param Entity[] $entities
 | |
|      */
 | |
|     protected function updateForEntities(array $entities): void
 | |
|     {
 | |
|         if (count($entities) === 0) {
 | |
|             return;
 | |
|         }
 | |
| 
 | |
|         $parser = CrossLinkParser::createWithEntityResolvers();
 | |
|         $references = [];
 | |
| 
 | |
|         $this->dropReferencesFromEntities($entities);
 | |
| 
 | |
|         foreach ($entities as $entity) {
 | |
|             $models = $parser->extractLinkedModels($entity->getAttribute($entity->htmlField));
 | |
| 
 | |
|             foreach ($models as $model) {
 | |
|                 $references[] = [
 | |
|                     'from_id'   => $entity->id,
 | |
|                     'from_type' => $entity->getMorphClass(),
 | |
|                     'to_id'     => $model->id,
 | |
|                     'to_type'   => $model->getMorphClass(),
 | |
|                 ];
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         foreach (array_chunk($references, 1000) as $referenceDataChunk) {
 | |
|             Reference::query()->insert($referenceDataChunk);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Delete all the existing references originating from the given entities.
 | |
|      * @param Entity[] $entities
 | |
|      */
 | |
|     protected function dropReferencesFromEntities(array $entities): void
 | |
|     {
 | |
|         $IdsByType = [];
 | |
| 
 | |
|         foreach ($entities as $entity) {
 | |
|             $type = $entity->getMorphClass();
 | |
|             if (!isset($IdsByType[$type])) {
 | |
|                 $IdsByType[$type] = [];
 | |
|             }
 | |
| 
 | |
|             $IdsByType[$type][] = $entity->id;
 | |
|         }
 | |
| 
 | |
|         foreach ($IdsByType as $type => $entityIds) {
 | |
|             Reference::query()
 | |
|                 ->where('from_type', '=', $type)
 | |
|                 ->whereIn('from_id', $entityIds)
 | |
|                 ->delete();
 | |
|         }
 | |
|     }
 | |
| }
 |