diff --git a/src/Symfony/Component/Console/CHANGELOG.md b/src/Symfony/Component/Console/CHANGELOG.md index 2922967b1261d..a97a4a7ad4a2b 100644 --- a/src/Symfony/Component/Console/CHANGELOG.md +++ b/src/Symfony/Component/Console/CHANGELOG.md @@ -7,6 +7,7 @@ CHANGELOG * added `setInputs()` method to CommandTester for ease testing of commands expecting inputs * added `setStream()` and `getStream()` methods to Input (implement StreamableInputInterface) * added StreamableInputInterface +* added LockableTrait 3.1.0 ----- diff --git a/src/Symfony/Component/Console/Command/LockableTrait.php b/src/Symfony/Component/Console/Command/LockableTrait.php new file mode 100644 index 0000000000000..30f8846768bd3 --- /dev/null +++ b/src/Symfony/Component/Console/Command/LockableTrait.php @@ -0,0 +1,63 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Command; + +use Symfony\Component\Console\Exception\LogicException; +use Symfony\Component\Console\Exception\RuntimeException; +use Symfony\Component\Filesystem\LockHandler; + +/** + * Basic lock feature for commands. + * + * @author Fabien Potencier + */ +trait LockableTrait +{ + protected $lockHandler; + + /** + * Locks a command. + * + * @return bool + */ + protected function lock($name = null, $blocking = false) + { + if (!class_exists(LockHandler::class)) { + throw new RuntimeException('To enable the locking feature you must install the symfony/filesystem component.'); + } + + if (null !== $this->lockHandler) { + throw new LogicException('A lock is already in place.'); + } + + $this->lockHandler = new LockHandler($name ?: $this->getName()); + + if (!$this->lockHandler->lock($blocking)) { + $this->lockHandler = null; + + return false; + } + + return true; + } + + /** + * Releases the command lock if there is one. + */ + protected function release() + { + if ($this->lockHandler) { + $this->lockHandler->release(); + $this->lockHandler = null; + } + } +} diff --git a/src/Symfony/Component/Console/Tests/Command/LockableTraitTest.php b/src/Symfony/Component/Console/Tests/Command/LockableTraitTest.php new file mode 100644 index 0000000000000..828ba163b6d0e --- /dev/null +++ b/src/Symfony/Component/Console/Tests/Command/LockableTraitTest.php @@ -0,0 +1,58 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Tests\Command; + +use Symfony\Component\Console\Tester\CommandTester; +use Symfony\Component\Filesystem\LockHandler; + +class LockableTraitTest extends \PHPUnit_Framework_TestCase +{ + protected static $fixturesPath; + + public static function setUpBeforeClass() + { + self::$fixturesPath = __DIR__.'/../Fixtures/'; + require_once self::$fixturesPath.'/FooLockCommand.php'; + require_once self::$fixturesPath.'/FooLock2Command.php'; + } + + public function testLockIsReleased() + { + $command = new \FooLockCommand(); + + $tester = new CommandTester($command); + $this->assertSame(2, $tester->execute(array())); + $this->assertSame(2, $tester->execute(array())); + } + + public function testLockReturnsFalseIfAlreadyLockedByAnotherCommand() + { + $command = new \FooLockCommand(); + + $lock = new LockHandler($command->getName()); + $lock->lock(); + + $tester = new CommandTester($command); + $this->assertSame(1, $tester->execute(array())); + + $lock->release(); + $this->assertSame(2, $tester->execute(array())); + } + + public function testMultipleLockCallsThrowLogicException() + { + $command = new \FooLock2Command(); + + $tester = new CommandTester($command); + $this->assertSame(1, $tester->execute(array())); + } +} diff --git a/src/Symfony/Component/Console/Tests/Fixtures/FooLock2Command.php b/src/Symfony/Component/Console/Tests/Fixtures/FooLock2Command.php new file mode 100644 index 0000000000000..4e4656f20f2d4 --- /dev/null +++ b/src/Symfony/Component/Console/Tests/Fixtures/FooLock2Command.php @@ -0,0 +1,28 @@ +setName('foo:lock2'); + } + + protected function execute(InputInterface $input, OutputInterface $output) + { + try { + $this->lock(); + $this->lock(); + } catch (LogicException $e) { + return 1; + } + + return 2; + } +} diff --git a/src/Symfony/Component/Console/Tests/Fixtures/FooLockCommand.php b/src/Symfony/Component/Console/Tests/Fixtures/FooLockCommand.php new file mode 100644 index 0000000000000..dfa28a6bec1f1 --- /dev/null +++ b/src/Symfony/Component/Console/Tests/Fixtures/FooLockCommand.php @@ -0,0 +1,27 @@ +setName('foo:lock'); + } + + protected function execute(InputInterface $input, OutputInterface $output) + { + if (!$this->lock()) { + return 1; + } + + $this->release(); + + return 2; + } +} diff --git a/src/Symfony/Component/Console/composer.json b/src/Symfony/Component/Console/composer.json index cbd0b22d7d4a2..cb73a00b8d887 100644 --- a/src/Symfony/Component/Console/composer.json +++ b/src/Symfony/Component/Console/composer.json @@ -21,11 +21,13 @@ }, "require-dev": { "symfony/event-dispatcher": "~2.8|~3.0", + "symfony/filesystem": "~2.8|~3.0", "symfony/process": "~2.8|~3.0", "psr/log": "~1.0" }, "suggest": { "symfony/event-dispatcher": "", + "symfony/filesystem": "", "symfony/process": "", "psr/log": "For using the console logger" }, pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy