├── .gitignore ├── Annotations └── Lockable.php ├── Controller └── DefaultController.php ├── DependencyInjection ├── Configuration.php └── EPDoctrineLockExtension.php ├── EPDoctrineLockBundle.php ├── Entity ├── ObjectLock.php └── ObjectLockRepository.php ├── EventListener └── DoctrineEventSubscriber.php ├── Exception ├── LockedEntityException.php └── LockedObjectException.php ├── Params └── ObjectLockParams.php ├── README.md ├── Resources └── config │ ├── doctrine │ └── ObjectLock.orm.yml │ ├── routing.yml │ └── services.yml ├── Service ├── ObjectLocker.php └── ObjectLockerInterface.php ├── Tests └── Controller │ └── DefaultControllerTest.php ├── Traits └── LockableTrait.php └── composer.json /.gitignore: -------------------------------------------------------------------------------- 1 | phpunit.xml 2 | vendor 3 | composer.lock 4 | composer.phar 5 | .php_cs.cache -------------------------------------------------------------------------------- /Annotations/Lockable.php: -------------------------------------------------------------------------------- 1 | $value) { 26 | if (!property_exists($this, $key)) { 27 | throw new \InvalidArgumentException(sprintf('Property "%s" does not exist', $key)); 28 | } 29 | $this->$key = $value; 30 | } 31 | } 32 | 33 | /** 34 | * @return boolean 35 | */ 36 | public function isPreUpdateCheckEnabled() 37 | { 38 | return $this->preUpdateCheckEnabled; 39 | } 40 | 41 | /** 42 | * @return boolean 43 | */ 44 | public function isPreDeleteCheckEnabled() 45 | { 46 | return $this->preDeleteCheckEnabled; 47 | } 48 | } -------------------------------------------------------------------------------- /Controller/DefaultController.php: -------------------------------------------------------------------------------- 1 | root('ep_doctrine_lock'); 22 | 23 | // Here you should define the parameters that are allowed to 24 | // configure your bundle. See the documentation linked above for 25 | // more information on that topic. 26 | 27 | return $treeBuilder; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /DependencyInjection/EPDoctrineLockExtension.php: -------------------------------------------------------------------------------- 1 | processConfiguration($configuration, $configs); 24 | 25 | $loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config')); 26 | $loader->load('services.yml'); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /EPDoctrineLockBundle.php: -------------------------------------------------------------------------------- 1 | id; 46 | } 47 | 48 | /** 49 | * @return string 50 | */ 51 | public function getObjectClass() 52 | { 53 | return $this->objectClass; 54 | } 55 | 56 | /** 57 | * @param string $objectClass 58 | * @return $this 59 | */ 60 | public function setObjectClass($objectClass) 61 | { 62 | $this->objectClass = $objectClass; 63 | 64 | return $this; 65 | } 66 | 67 | /** 68 | * @return boolean 69 | */ 70 | public function isFullLocked() 71 | { 72 | return $this->fullLocked; 73 | } 74 | 75 | /** 76 | * @param boolean $fullLocked 77 | * @return $this 78 | */ 79 | public function setFullLocked($fullLocked) 80 | { 81 | $this->fullLocked = $fullLocked; 82 | 83 | return $this; 84 | } 85 | 86 | /** 87 | * @return boolean 88 | */ 89 | public function isInsertLocked() 90 | { 91 | return $this->insertLocked; 92 | } 93 | 94 | /** 95 | * @param boolean $insertLocked 96 | * @return $this 97 | */ 98 | public function setInsertLocked($insertLocked) 99 | { 100 | $this->insertLocked = $insertLocked; 101 | 102 | return $this; 103 | } 104 | 105 | /** 106 | * @return boolean 107 | */ 108 | public function isUpdateLocked() 109 | { 110 | return $this->updateLocked; 111 | } 112 | 113 | /** 114 | * @param boolean $updateLocked 115 | * @return $this 116 | */ 117 | public function setUpdateLocked($updateLocked) 118 | { 119 | $this->updateLocked = $updateLocked; 120 | 121 | return $this; 122 | } 123 | 124 | /** 125 | * @return boolean 126 | */ 127 | public function isDeleteLocked() 128 | { 129 | return $this->deleteLocked; 130 | } 131 | 132 | /** 133 | * @param boolean $deleteLocked 134 | * @return $this 135 | */ 136 | public function setDeleteLocked($deleteLocked) 137 | { 138 | $this->deleteLocked = $deleteLocked; 139 | 140 | return $this; 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /Entity/ObjectLockRepository.php: -------------------------------------------------------------------------------- 1 | accessor = $accessor; 33 | } 34 | 35 | public function getSubscribedEvents() 36 | { 37 | return [ 38 | Events::prePersist, 39 | Events::preRemove, 40 | Events::preUpdate, 41 | Events::loadClassMetadata, 42 | ]; 43 | } 44 | 45 | /** 46 | * @param LifecycleEventArgs $args 47 | * @return void 48 | * @throws LockedObjectException 49 | */ 50 | public function prePersist(LifecycleEventArgs $args) 51 | { 52 | $entity = $args->getEntity(); 53 | if($entity instanceof ObjectLock){ 54 | return; 55 | } 56 | $em = $args->getEntityManager(); 57 | $objectLocker = new ObjectLocker($em, $this->accessor); 58 | 59 | $isFullLocked = $objectLocker->isLocked($entity); 60 | if($isFullLocked){ 61 | throw new LockedObjectException('You tried insert row an fully locked object'); 62 | } 63 | $isInsertLocked = $objectLocker->isLocked($entity, ObjectLockParams::INSERT_LOCK); 64 | if($isInsertLocked){ 65 | throw new LockedObjectException('You tried insert row an insert locked object'); 66 | } 67 | return; 68 | } 69 | 70 | /** 71 | * @param LifecycleEventArgs $args 72 | * @throws LockedEntityException 73 | * @throws LockedObjectException 74 | */ 75 | public function preRemove(LifecycleEventArgs $args) 76 | { 77 | $entity = $args->getEntity(); 78 | if($entity instanceof ObjectLock){ 79 | return; 80 | } 81 | 82 | $em = $args->getEntityManager(); 83 | $objectLocker = new ObjectLocker($em, $this->accessor); 84 | 85 | $isFullLocked = $objectLocker->isLocked($entity); 86 | if($isFullLocked){ 87 | throw new LockedObjectException('You tried delete entity an fully locked object'); 88 | } 89 | $isInsertLocked = $objectLocker->isLocked($entity, ObjectLockParams::DELETE_LOCK); 90 | if($isInsertLocked){ 91 | throw new LockedObjectException('You tried delete entity an delete locked object'); 92 | } 93 | $isLockableEntity = $this->isLockableEntity($entity); 94 | if($isLockableEntity == false){ 95 | return; 96 | } 97 | if($isLockableEntity instanceof Lockable && $isLockableEntity->isPreDeleteCheckEnabled() == false){ 98 | return; 99 | } 100 | if($entity->isDeleteLocked()){ 101 | throw new LockedEntityException('You tried delete row that delete locked entity'); 102 | } 103 | return; 104 | } 105 | 106 | /** 107 | * @param LifecycleEventArgs $args 108 | * @throws LockedEntityException 109 | * @throws LockedObjectException 110 | */ 111 | public function preUpdate(LifecycleEventArgs $args) 112 | { 113 | $entity = $args->getEntity(); 114 | if($entity instanceof ObjectLock){ 115 | return; 116 | } 117 | $em = $args->getEntityManager(); 118 | $uow = $em->getUnitOfWork(); 119 | $changeset = $uow->getEntityChangeSet($entity); 120 | $objectLocker = new ObjectLocker($em, $this->accessor); 121 | 122 | $isFullLocked = $objectLocker->isLocked($entity); 123 | if($isFullLocked){ 124 | throw new LockedObjectException('You tried update row an fully locked object'); 125 | } 126 | $isUpdateLocked = $objectLocker->isLocked($entity, ObjectLockParams::UPDATE_LOCK); 127 | if($isUpdateLocked){ 128 | throw new LockedObjectException('You tried update row an update locked object'); 129 | } 130 | $isLockableEntity = $this->isLockableEntity($entity); 131 | if($isLockableEntity == false){ 132 | return; 133 | } 134 | if($isLockableEntity instanceof Lockable && $isLockableEntity->isPreUpdateCheckEnabled() == false){ 135 | return; 136 | } 137 | if(isset($changeset['updateLocked'])){ 138 | return; 139 | } 140 | if($entity->isUpdateLocked()){ 141 | throw new LockedEntityException('You tried update row an update locked entity'); 142 | } 143 | return; 144 | } 145 | 146 | /** 147 | * Add mapping to lockable entities 148 | * 149 | * @param LoadClassMetadataEventArgs $eventArgs 150 | * @return void 151 | */ 152 | public function loadClassMetadata(LoadClassMetadataEventArgs $eventArgs) 153 | { 154 | $reader = new AnnotationReader(); 155 | /** @var ClassMetadata $classMetadata */ 156 | $classMetadata = $eventArgs->getClassMetadata(); 157 | /** @var \ReflectionClass $reflClass */ 158 | $reflClass = $classMetadata->reflClass; 159 | 160 | if (!$reflClass || $reflClass->isAbstract()) { 161 | return; 162 | } 163 | $lockableAnnotation = $reader->getClassAnnotation($reflClass, 'EP\\DoctrineLockBundle\\Annotations\\Lockable'); 164 | if($lockableAnnotation !== null){ 165 | $this->mapLockable($classMetadata); 166 | } 167 | } 168 | 169 | /** 170 | * @param $entity 171 | * @return bool 172 | */ 173 | private function isLockableEntity($entity) 174 | { 175 | $reader = new AnnotationReader(); 176 | $reflClass = new \ReflectionClass($entity); 177 | $lockableAnnotation = $reader->getClassAnnotation($reflClass, 'EP\\DoctrineLockBundle\\Annotations\\Lockable'); 178 | if($lockableAnnotation == null){ 179 | return false; 180 | } 181 | if(!method_exists($entity, 'isUpdateLocked') || !method_exists($entity, 'isDeleteLocked')){ 182 | throw new \LogicException('Please use Lockable trait on '. $reflClass->getName()); 183 | } 184 | return $lockableAnnotation; 185 | } 186 | 187 | /** 188 | * map lockable fields if not mapped 189 | * 190 | * @param ClassMetadata $classMetadata 191 | */ 192 | private function mapLockable(ClassMetadata $classMetadata) 193 | { 194 | // Map update lock field 195 | if (!$classMetadata->hasField('updateLocked')) { 196 | $classMetadata->mapField( 197 | array( 198 | 'fieldName' => 'updateLocked', 199 | 'type' => 'boolean', 200 | 'nullable' => true, 201 | ) 202 | ); 203 | } 204 | 205 | // Map delete lock field 206 | if (!$classMetadata->hasField('deleteLocked')) { 207 | $classMetadata->mapField( 208 | array( 209 | 'fieldName' => 'deleteLocked', 210 | 'type' => 'boolean', 211 | 'nullable' => true, 212 | ) 213 | ); 214 | } 215 | 216 | // Map delete locked by field 217 | if (!$classMetadata->hasField('deleteLockedBy')) { 218 | $classMetadata->mapField( 219 | array( 220 | 'fieldName' => 'deleteLockedBy', 221 | 'type' => 'string', 222 | 'nullable' => true 223 | ) 224 | ); 225 | } 226 | 227 | // Map update locked by field 228 | if (!$classMetadata->hasField('updateLockedBy')) { 229 | $classMetadata->mapField( 230 | array( 231 | 'fieldName' => 'updateLockedBy', 232 | 'type' => 'string', 233 | 'nullable' => true 234 | ) 235 | ); 236 | } 237 | 238 | // Map delete locked time field 239 | if (!$classMetadata->hasField('deleteLockedTime')) { 240 | $classMetadata->mapField( 241 | array( 242 | 'fieldName' => 'deleteLockedTime', 243 | 'type' => 'datetime', 244 | 'nullable' => true 245 | ) 246 | ); 247 | } 248 | 249 | // Map update locked time field 250 | if (!$classMetadata->hasField('updateLockedTime')) { 251 | $classMetadata->mapField( 252 | array( 253 | 'fieldName' => 'updateLockedTime', 254 | 'type' => 'datetime', 255 | 'nullable' => true 256 | ) 257 | ); 258 | } 259 | } 260 | } -------------------------------------------------------------------------------- /Exception/LockedEntityException.php: -------------------------------------------------------------------------------- 1 | 14 | 15 | - Development steps can be followed from https://github.com/behramcelen/symfony-bundle-develop 16 | - A basic test and logic command can be found in https://github.com/behramcelen/symfony-bundle-develop/blob/master/src/AppBundle/Command/LockBundleTestCommand.php#L41 17 | 18 | 19 | Installation 20 | ============ 21 | 22 | Step 1: Download the Bundle 23 | --------------------------- 24 | 25 | Open a command console, go to your project directory and execute the 26 | following command to download the latest version of this bundle: 27 | 28 | ```bash 29 | $ composer require enterprisephp/doctrine-lock-bundle "dev-master" 30 | ``` 31 | 32 | This command requires you to have Composer installed globally, as explained 33 | in the [installation chapter](https://getcomposer.org/doc/00-intro.md) 34 | of the Composer documentation. 35 | 36 | Step 2: Enable the Bundle 37 | ------------------------- 38 | 39 | Then, enable the bundle by adding it to the list of registered bundles 40 | in the `app/AppKernel.php` file of your project: 41 | 42 | ```php 43 | get('ep.doctrine.object.locker'); 73 | //lock fully 74 | $objectLocker->lock(new DummyEntity()); 75 | //lock delete process 76 | $objectLocker->lock(new DummyEntity(), ObjectLockParams::DELETE_LOCK); 77 | //lock insert process 78 | $objectLocker->lock(new DummyEntity(), ObjectLockParams::INSERT_LOCK); 79 | //lock update process 80 | $objectLocker->lock(new DummyEntity(), ObjectLockParams::UPDATE_LOCK); 81 | ``` 82 | Doctrine Object Unlock 83 | --------------------------- 84 | ```php 85 | use EP\DoctrineLockBundle\Params\ObjectLockParams; 86 | // ... 87 | $objectLocker = $container->get('ep.doctrine.object.locker'); 88 | //unlock full lock 89 | $objectLocker->unlock(new DummyEntity()); 90 | //unlock delete process 91 | $objectLocker->unlock(new DummyEntity(), ObjectLockParams::DELETE_LOCK); 92 | //unlock insert process 93 | $objectLocker->unlock(new DummyEntity(), ObjectLockParams::INSERT_LOCK); 94 | //unlock update process 95 | $objectLocker->unlock(new DummyEntity(), ObjectLockParams::UPDATE_LOCK); 96 | ``` 97 | Doctrine Object Switch Lock 98 | --------------------------- 99 | ```php 100 | use EP\DoctrineLockBundle\Params\ObjectLockParams; 101 | // ... 102 | $objectLocker = $container->get('ep.doctrine.object.locker'); 103 | //switch full lock 104 | $objectLocker->switchLock(new DummyEntity()); 105 | //switch delete process 106 | $objectLocker->switchLock(new DummyEntity(), ObjectLockParams::DELETE_LOCK); 107 | //switch insert process 108 | $objectLocker->switchLock(new DummyEntity(), ObjectLockParams::INSERT_LOCK); 109 | //unswitchlock update process 110 | $objectLocker->switchLock(new DummyEntity(), ObjectLockParams::UPDATE_LOCK); 111 | ``` 112 | Doctrine Object Is Locked 113 | --------------------------- 114 | ```php 115 | use EP\DoctrineLockBundle\Params\ObjectLockParams; 116 | // ... 117 | $objectLocker = $container->get('ep.doctrine.object.locker'); 118 | //is full locked 119 | $objectLocker->isLocked(new DummyEntity()); 120 | //is delete locked 121 | $objectLocker->isLocked(new DummyEntity(), ObjectLockParams::DELETE_LOCK); 122 | //is insert locked 123 | $objectLocker->isLocked(new DummyEntity(), ObjectLockParams::INSERT_LOCK); 124 | //is update locked 125 | $objectLocker->isLocked(new DummyEntity(), ObjectLockParams::UPDATE_LOCK); 126 | ``` 127 | ### Example Use ### 128 | ```php 129 | $objectLocker = $container->get('ep.doctrine.object.locker'); 130 | //lock object 131 | $objectLocker->lock(new DummyEntity()); 132 | $em->persist(new DummyEntity()); // this will throw LockedObjectException 133 | ``` 134 | 135 | Doctrine Entity Lock 136 | --------------------------- 137 | #### Add Lockable annotation and lockable trait #### 138 | ```php 139 | namespace AppBundle\Entity; 140 | 141 | use EP\DoctrineLockBundle\Traits\LockableTrait; 142 | use EP\DoctrineLockBundle\Annotations\Lockable; 143 | 144 | /** 145 | * @Lockable 146 | */ 147 | class DummyEntity 148 | { 149 | use LockableTrait; 150 | // ... 151 | ``` 152 | #### Example Use #### 153 | ```php 154 | //create new dummy entity 155 | $dummyEntity = new DummyEntity(); 156 | $dummyEntity 157 | ->setTitle('Dummy Entity Title') 158 | ->setDescription('Dummy Entity Description') 159 | ->setUpdateLocked(true) //lock entity for update process 160 | ->setDeleteLocked(true) //lock entity for delete process 161 | ; 162 | $em->persist($dummyEntity); 163 | $em->flush(); 164 | 165 | $dummyEntity->setTitle('Update Dummy Entity Title'); 166 | $em->persist($dummyEntity); 167 | $em->flush(); // this will throw LockedEntityException because entity have update lock 168 | 169 | $em->remove($dummyEntity); // this will throw LockedEntityException because entity have delete lock 170 | ``` 171 | ##### Unlock Entity Lock ##### 172 | ```php 173 | //unlock update lock 174 | $dummyEntity->setUpdateLocked(false); 175 | //unlock delete lock 176 | $dummyEntity->setDeleteLocked(false); 177 | ``` 178 | -------------------------------------------------------------------------------- /Resources/config/doctrine/ObjectLock.orm.yml: -------------------------------------------------------------------------------- 1 | EP\DoctrineLockBundle\Entity\ObjectLock: 2 | type: entity 3 | table: ep_object_lock 4 | repositoryClass: EP\DoctrineLockBundle\Entity\ObjectLockRepository 5 | id: 6 | id: 7 | type: integer 8 | id: true 9 | generator: 10 | strategy: AUTO 11 | fields: 12 | objectClass: 13 | column: object_class 14 | unique: true 15 | type: string 16 | length: 255 17 | nullable: false 18 | fullLocked: 19 | type: boolean 20 | insertLocked: 21 | type: boolean 22 | updateLocked: 23 | type: boolean 24 | deleteLocked: 25 | type: boolean 26 | -------------------------------------------------------------------------------- /Resources/config/routing.yml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EnterprisePHP/EPDoctrineLockBundle/1dd56b5e06c46950b849922bacc886468f0e1f33/Resources/config/routing.yml -------------------------------------------------------------------------------- /Resources/config/services.yml: -------------------------------------------------------------------------------- 1 | parameters: 2 | ep.doctrine.object.locker.class: EP\DoctrineLockBundle\Service\ObjectLocker 3 | ep.doctrine.event.subscriber.class: EP\DoctrineLockBundle\EventListener\DoctrineEventSubscriber 4 | 5 | services: 6 | ep.doctrine.object.locker: 7 | class: "%ep.doctrine.object.locker.class%" 8 | arguments: ["@doctrine.orm.entity_manager", "@property_accessor"] 9 | 10 | ep.doctrine.event.subscriber: 11 | class: "%ep.doctrine.event.subscriber.class%" 12 | arguments: ["@property_accessor"] 13 | tags: 14 | - { name: doctrine.event_subscriber } -------------------------------------------------------------------------------- /Service/ObjectLocker.php: -------------------------------------------------------------------------------- 1 | em = $em; 32 | $this->accessor = $accessor; 33 | } 34 | 35 | /** 36 | * @param $object 37 | * @param string $lockType 38 | * @return bool 39 | * @throws \Exception 40 | */ 41 | public function lock($object, $lockType = ObjectLockParams::FULL_LOCK) 42 | { 43 | $objectClassName = $this->getObjectClassName($object); 44 | $objectDetail = $this->getObjectDetail($objectClassName); 45 | if(!$objectDetail){ 46 | $objectDetail = $this->setupObjectDetail($objectClassName); 47 | } 48 | $this->accessor->setValue($objectDetail, $lockType, true); 49 | $this->em->persist($objectDetail); 50 | $this->em->flush(); 51 | 52 | return true; 53 | } 54 | 55 | /** 56 | * @param $object object 57 | * @param string $lockType 58 | * @return bool 59 | * @throws \Exception 60 | */ 61 | public function unlock($object, $lockType = ObjectLockParams::FULL_LOCK) 62 | { 63 | $objectClassName = $this->getObjectClassName($object); 64 | $objectDetail = $this->getObjectDetail($objectClassName); 65 | if(!$objectDetail){ 66 | $objectDetail = $this->setupObjectDetail($objectClassName); 67 | } 68 | $this->accessor->setValue($objectDetail, $lockType, false); 69 | $this->em->persist($objectDetail); 70 | $this->em->flush(); 71 | 72 | return true; 73 | } 74 | 75 | /** 76 | * @param $object 77 | * @param string $lockType 78 | * @return bool 79 | * @throws \Exception 80 | */ 81 | public function switchLock($object, $lockType = ObjectLockParams::FULL_LOCK) 82 | { 83 | $objectClassName = $this->getObjectClassName($object); 84 | $objectDetail = $this->getObjectDetail($objectClassName); 85 | if(!$objectDetail){ 86 | $objectDetail = $this->setupObjectDetail($objectClassName); 87 | } 88 | if($this->accessor->getValue($objectDetail, $lockType) === true){ 89 | $this->accessor->setValue($objectDetail, $lockType, false); 90 | }else{ 91 | $this->accessor->setValue($objectDetail, $lockType, true); 92 | } 93 | $this->em->persist($objectDetail); 94 | $this->em->flush(); 95 | 96 | return true; 97 | } 98 | 99 | /** 100 | * @param $object 101 | * @param string $lockType 102 | * @return boolean 103 | * @throws \Exception 104 | */ 105 | public function isLocked($object, $lockType = ObjectLockParams::FULL_LOCK) 106 | { 107 | $objectClassName = $this->getObjectClassName($object); 108 | $objectDetail = $this->getObjectDetail($objectClassName); 109 | if(!$objectDetail){ 110 | $objectDetail = $this->setupObjectDetail($objectClassName); 111 | } 112 | return $this->accessor->getValue($objectDetail, $lockType); 113 | } 114 | 115 | /** 116 | * @param $object 117 | * @return string 118 | * @throws MappingException 119 | * @throws \Exception 120 | */ 121 | private function getObjectClassName($object) 122 | { 123 | try { 124 | $objectName = $this->em->getMetadataFactory()->getMetadataFor(get_class($object))->getName(); 125 | } catch (MappingException $e) { 126 | throw new \Exception('Given object ' . get_class($object) . ' is not a Doctrine Entity. '); 127 | } 128 | 129 | return $objectName; 130 | } 131 | 132 | /** 133 | * @param $objectClassName 134 | * @return ObjectLock|null 135 | */ 136 | private function getObjectDetail($objectClassName) 137 | { 138 | return $this->em->getRepository('EPDoctrineLockBundle:ObjectLock')->findOneBy([ 139 | 'objectClass' => $objectClassName 140 | ]); 141 | } 142 | 143 | /** 144 | * @param $objectClassName string 145 | * @return ObjectLock 146 | */ 147 | private function setupObjectDetail($objectClassName) 148 | { 149 | $objectLock = new ObjectLock(); 150 | $objectLock 151 | ->setObjectClass($objectClassName) 152 | ->setFullLocked(false) 153 | ->setInsertLocked(false) 154 | ->setUpdateLocked(false) 155 | ->setDeleteLocked(false) 156 | ; 157 | $this->em->persist($objectLock); 158 | $this->em->flush(); 159 | return $objectLock; 160 | } 161 | 162 | /** 163 | * @param $entity 164 | * @return bool 165 | */ 166 | public function isLockableEntity($entity) 167 | { 168 | $reader = new AnnotationReader(); 169 | $reflClass = new \ReflectionClass($entity); 170 | $lockableAnnotation = $reader->getClassAnnotation($reflClass, 'EP\\DoctrineLockBundle\\Annotations\\Lockable'); 171 | if($lockableAnnotation == null){ 172 | return false; 173 | } 174 | if(!method_exists($entity, 'isUpdateLocked') || !method_exists($entity, 'isDeleteLocked')){ 175 | throw new \LogicException('Please use Lockable trait on '. $reflClass->getName()); 176 | } 177 | return true; 178 | } 179 | 180 | /** 181 | * @return EntityManager 182 | */ 183 | public function getEntityManager() 184 | { 185 | return $this->em; 186 | } 187 | } 188 | -------------------------------------------------------------------------------- /Service/ObjectLockerInterface.php: -------------------------------------------------------------------------------- 1 | updateLocked; 47 | } 48 | 49 | /** 50 | * @param boolean $updateLocked 51 | * @return $this 52 | */ 53 | public function setUpdateLocked($updateLocked) 54 | { 55 | $this->updateLocked = $updateLocked; 56 | 57 | return $this; 58 | } 59 | 60 | /** 61 | * @return boolean 62 | */ 63 | public function isDeleteLocked() 64 | { 65 | return $this->deleteLocked; 66 | } 67 | 68 | /** 69 | * @param boolean $deleteLocked 70 | * @return $this 71 | */ 72 | public function setDeleteLocked($deleteLocked) 73 | { 74 | $this->deleteLocked = $deleteLocked; 75 | 76 | return $this; 77 | } 78 | 79 | /** 80 | * @return string 81 | */ 82 | public function getUpdateLockedBy() 83 | { 84 | return $this->updateLockedBy; 85 | } 86 | 87 | /** 88 | * @param string $updateLockedBy 89 | * @return $this 90 | */ 91 | public function setUpdateLockedBy($updateLockedBy) 92 | { 93 | $this->updateLockedBy = $updateLockedBy; 94 | 95 | return $this; 96 | } 97 | 98 | /** 99 | * @return \DateTime 100 | */ 101 | public function getUpdateLockedTime() 102 | { 103 | return $this->updateLockedTime; 104 | } 105 | 106 | /** 107 | * @param \DateTime $updateLockedTime 108 | * @return $this 109 | */ 110 | public function setUpdateLockedTime($updateLockedTime) 111 | { 112 | $this->updateLockedTime = $updateLockedTime; 113 | 114 | return $this; 115 | } 116 | 117 | /** 118 | * @return string 119 | */ 120 | public function getDeleteLockedBy() 121 | { 122 | return $this->deleteLockedBy; 123 | } 124 | 125 | /** 126 | * @param string $deleteLockedBy 127 | * @return $this 128 | */ 129 | public function setDeleteLockedBy($deleteLockedBy) 130 | { 131 | $this->deleteLockedBy = $deleteLockedBy; 132 | 133 | return $this; 134 | } 135 | 136 | /** 137 | * @return \DateTime 138 | */ 139 | public function getDeleteLockedTime() 140 | { 141 | return $this->deleteLockedTime; 142 | } 143 | 144 | /** 145 | * @param \DateTime $deleteLockedTime 146 | * @return $this 147 | */ 148 | public function setDeleteLockedTime($deleteLockedTime) 149 | { 150 | $this->deleteLockedTime = $deleteLockedTime; 151 | 152 | return $this; 153 | } 154 | } 155 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "enterprisephp/doctrine-lock-bundle", 3 | "type": "symfony-bundle", 4 | "description": "Lock object against delete, update events", 5 | "keywords": ["doctrine", "lock", "lockable"], 6 | "homepage": "https://enterprisephp.github.io", 7 | "license": "MIT", 8 | "authors": [ 9 | { 10 | "name": "Behram ÇELEN", 11 | "email": "behramcelen@gmail.com" 12 | } 13 | ], 14 | "require": { 15 | "php": "^5.5.9|~7.0", 16 | "psr/log": "^1.0", 17 | "symfony/framework-bundle": "^2.7|^3.0" 18 | }, 19 | 20 | "require-dev": { 21 | "sensio/framework-extra-bundle": "^3.0", 22 | "symfony/phpunit-bridge": "~2.7|^3.0", 23 | "symfony/form": "^2.7|^3.0", 24 | "symfony/validator": "^2.7|^3.0", 25 | "symfony/serializer": "^2.7|^3.0", 26 | "symfony/yaml": "^2.7|^3.0", 27 | "symfony/security-bundle": "^2.7|^3.0", 28 | "symfony/web-profiler-bundle": "^2.7|^3.0", 29 | "symfony/twig-bundle": "^2.7|^3.0", 30 | "symfony/browser-kit": "^2.7|^3.0", 31 | "symfony/dependency-injection": "^2.7|^3.0", 32 | "jms/serializer-bundle": "^1.0" 33 | }, 34 | 35 | "suggest": { 36 | "sensio/framework-extra-bundle": "Add support for route annotations and the view response listener, requires ^3.0", 37 | "jms/serializer-bundle": "Add support for advanced serialization capabilities, recommended, requires ^1.0", 38 | "symfony/expression-language": "Add support for using the expression language in the routing, requires ^2.7|^3.0", 39 | "symfony/serializer": "Add support for basic serialization capabilities and xml decoding, requires ^2.7|^3.0", 40 | "symfony/validator": "Add support for validation capabilities in the ParamFetcher, requires ^2.7|^3.0" 41 | }, 42 | 43 | "autoload":{ 44 | "psr-4":{ 45 | "EP\\DoctrineLockBundle\\": "" 46 | } 47 | }, 48 | 49 | "extra": { 50 | "branch-alias": { 51 | "dev-master": "0.1-dev" 52 | } 53 | } 54 | } --------------------------------------------------------------------------------