[WebProfiler] replaced the import/export feature from the web interface to a CLI tool
This commit is contained in:
parent
b554961a5b
commit
f38536ab79
|
@ -0,0 +1,75 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Bundle\WebProfilerBundle\Command;
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\HttpKernel\Profiler\Profiler;
|
||||
|
||||
/**
|
||||
* Exports a profile.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
class ExportCommand extends Command
|
||||
{
|
||||
private $profiler;
|
||||
|
||||
public function __construct(Profiler $profiler = null)
|
||||
{
|
||||
$this->profiler = $profiler;
|
||||
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function isEnabled()
|
||||
{
|
||||
if (null === $this->profiler) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return parent::isEnabled();
|
||||
}
|
||||
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setName('profiler:export')
|
||||
->setDescription('Exports a profile')
|
||||
->setDefinition(array(
|
||||
new InputArgument('token', InputArgument::REQUIRED, 'The profile token'),
|
||||
))
|
||||
->setHelp(<<<EOF
|
||||
The <info>%command.name%</info> command exports a profile to the standard output:
|
||||
|
||||
<info>php %command.full_name% profile_token</info>
|
||||
EOF
|
||||
)
|
||||
;
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$token = $input->getArgument('token');
|
||||
|
||||
if (!$profile = $this->profiler->loadProfile($token)) {
|
||||
throw new \LogicException(sprintf('Profile with token "%s" does not exist.', $token));
|
||||
}
|
||||
|
||||
$output->writeln($this->profiler->export($profile), OutputInterface::OUTPUT_RAW);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,90 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Bundle\WebProfilerBundle\Command;
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\HttpKernel\Profiler\Profiler;
|
||||
|
||||
/**
|
||||
* Imports a profile.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
class ImportCommand extends Command
|
||||
{
|
||||
private $profiler;
|
||||
|
||||
public function __construct(Profiler $profiler = null)
|
||||
{
|
||||
$this->profiler = $profiler;
|
||||
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function isEnabled()
|
||||
{
|
||||
if (null === $this->profiler) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return parent::isEnabled();
|
||||
}
|
||||
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setName('profiler:import')
|
||||
->setDescription('Imports a profile')
|
||||
->setDefinition(array(
|
||||
new InputArgument('filename', InputArgument::OPTIONAL, 'The profile path'),
|
||||
))
|
||||
->setHelp(<<<EOF
|
||||
The <info>%command.name%</info> command imports a profile:
|
||||
|
||||
<info>php %command.full_name% profile_filepath</info>
|
||||
|
||||
You can also pipe the profile via STDIN:
|
||||
|
||||
<info>cat profile_file | php %command.full_name%</info>
|
||||
EOF
|
||||
)
|
||||
;
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$data = '';
|
||||
if ($input->getArgument('filename')) {
|
||||
$data = file_get_contents($input->getArgument('filename'));
|
||||
} else {
|
||||
if (0 !== ftell(STDIN)) {
|
||||
throw new \RuntimeException('Please provide a filename or pipe the profile to STDIN.');
|
||||
}
|
||||
|
||||
while (!feof(STDIN)) {
|
||||
$data .= fread(STDIN, 1024);
|
||||
}
|
||||
}
|
||||
|
||||
if (!$profile = $this->profiler->import($data)) {
|
||||
throw new \LogicException('The profile already exists in the database.');
|
||||
}
|
||||
|
||||
$output->writeln(sprintf('Profile "%s" has been successfully imported.', $profile->getToken()));
|
||||
}
|
||||
}
|
|
@ -111,33 +111,6 @@ class ProfilerController
|
|||
)), 200, array('Content-Type' => 'text/html'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Exports data for a given token.
|
||||
*
|
||||
* @param string $token The profiler token
|
||||
*
|
||||
* @return Response A Response instance
|
||||
*
|
||||
* @throws NotFoundHttpException
|
||||
*/
|
||||
public function exportAction($token)
|
||||
{
|
||||
if (null === $this->profiler) {
|
||||
throw new NotFoundHttpException('The profiler must be enabled.');
|
||||
}
|
||||
|
||||
$this->profiler->disable();
|
||||
|
||||
if (!$profile = $this->profiler->loadProfile($token)) {
|
||||
throw new NotFoundHttpException(sprintf('Token "%s" does not exist.', $token));
|
||||
}
|
||||
|
||||
return new Response($this->profiler->export($profile), 200, array(
|
||||
'Content-Type' => 'text/plain',
|
||||
'Content-Disposition' => 'attachment; filename= '.$token.'.txt',
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Purges all tokens.
|
||||
*
|
||||
|
@ -157,36 +130,6 @@ class ProfilerController
|
|||
return new RedirectResponse($this->generator->generate('_profiler_info', array('about' => 'purge')), 302, array('Content-Type' => 'text/html'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Imports token data.
|
||||
*
|
||||
* @param Request $request The current HTTP Request
|
||||
*
|
||||
* @return Response A Response instance
|
||||
*
|
||||
* @throws NotFoundHttpException
|
||||
*/
|
||||
public function importAction(Request $request)
|
||||
{
|
||||
if (null === $this->profiler) {
|
||||
throw new NotFoundHttpException('The profiler must be enabled.');
|
||||
}
|
||||
|
||||
$this->profiler->disable();
|
||||
|
||||
$file = $request->files->get('file');
|
||||
|
||||
if (empty($file) || !$file->isValid()) {
|
||||
return new RedirectResponse($this->generator->generate('_profiler_info', array('about' => 'upload_error')), 302, array('Content-Type' => 'text/html'));
|
||||
}
|
||||
|
||||
if (!$profile = $this->profiler->import(file_get_contents($file->getPathname()))) {
|
||||
return new RedirectResponse($this->generator->generate('_profiler_info', array('about' => 'already_exists')), 302, array('Content-Type' => 'text/html'));
|
||||
}
|
||||
|
||||
return new RedirectResponse($this->generator->generate('_profiler', array('token' => $profile->getToken())), 302, array('Content-Type' => 'text/html'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays information page.
|
||||
*
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
<?xml version="1.0" ?>
|
||||
|
||||
<container xmlns="http://symfony.com/schema/dic/services"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
|
||||
|
||||
<parameters>
|
||||
<parameter key="web_profiler.command.import.class">Symfony\Bundle\WebProfilerBundle\Command\ImportCommand</parameter>
|
||||
<parameter key="web_profiler.command.export.class">Symfony\Bundle\WebProfilerBundle\Command\ExportCommand</parameter>
|
||||
</parameters>
|
||||
|
||||
<services>
|
||||
<service id="web_profiler.command.import" class="%web_profiler.command.import.class%">
|
||||
<argument type="service" id="profiler" on-invalid="null" />
|
||||
<tag name="console.command" />
|
||||
</service>
|
||||
|
||||
<service id="web_profiler.command.export" class="%web_profiler.command.export.class%">
|
||||
<argument type="service" id="profiler" on-invalid="null" />
|
||||
<tag name="console.command" />
|
||||
</service>
|
||||
</services>
|
||||
</container>
|
|
@ -1,27 +1,10 @@
|
|||
<div class="search import clearfix" id="adminBar">
|
||||
<h3>
|
||||
<img style="margin: 0 5px 0 0; vertical-align: middle; height: 16px" width="16" height="16" alt="Import" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAADo0lEQVR42u2XS0hUURjHD5njA1oYbXQ2MqCmIu2iEEISUREEEURxFB8ovt+DEsLgaxBRQQeUxnQ0ZRYSQasgiDaFqxAy2jUtCjdCoEjFwHj6/+F+dbvN6PQAN37wm++c7/z/35x7uPcOo7TW58rFBs59A7GGQ51XBAIBlZmZuYOhE1zm/A/4PxvY3NwMO53OYEJCgp+nccqXXQc94D54boAxalyLNayNtra2NJmbmzvOyMj4cRqoKYK4AsZzc3Nft7e3f5qZmTnCpk8Ix6xxjRpDGzmkUU5Ozuu2trZP09PTR+vr6ycbGxtaWFtbC9fU1AQTExPdmNNzLSUlZXt4ePhANNGghlp6lDWkkcvlOsCX6LNYXV0N8BTS0tK2cDJfWIsFaumhV0lIIxzXl5WVFX0aPp8vhDwJbMnJyc6JiYkji8YP7oI4YowfmDX00KskOHG73UfLy8vahB/cBXFSW1pa2kPOA7RdqqysfGtaCyOXA2VGgmvUiJ5e9lD8qKioeOv1ejVZXFwMI5eLEWOFWgh5Etg4J0lJSTdwYiHxLSwseFi3Yg5qRE8veyh+TE1Nhebn5zWZnZ31mE2okTxmM6WlpS7xeDyeQ2Qb61bMQQ214mMPVVxc7MJuNBkfHz9EtplNmEcET4JPfL29va+i6azR19f3UnzV1dUrqqqqyocT0KSzs/OV1YB6ROrr67fF19TU9DSazhp1dXXPxdfS0vJQNTY2+sfGxjSpra19YTWgHhHs/pn40OhRNJ0lLuON+kF8ra2tY9yAe3R0VBMc6wfr84n6b1BDrfiam5snImgczObAq7ylv7//q/hGRkbuqMHBwTt4Q2nS3d39jSKzCfXfoKarq+ur+NhD1owLcNrt9h3OTXGrqKgoKJ6hoaFD5DhuIA43xiGyJoWFhUGKxYXaL3CNGtH39PR8Zg9jzREfH+8vKCgI4krDRu0GcGVnZ78ZGBg4ER/Wf+4OVzOMRhrwFE6ysrLe0EQzaopII65RI3p478lVp6am7uDmPJY11F44HI7dsrKyfc5Nnj1km5Lo6Oiw4cdnD1kLJSUl++np6btsQjhmzayB5x29uGp3fn5+EPMw66eBX8b3yHZlDdyRdtzN75F1LED7kR6gMA7E6HsMrqpogbv5KngM9Bk8MbTKwAYmQSiCdhd4wW0VazQ0NNwEXrALNDHGS+A2UFHIA3smj/rX4JvrT7GBSRDi/J8Db8e/JY/5jLj4Y3KxgfPfwHc53iL+IQDMOgAAAABJRU5ErkJggg==">
|
||||
Admin
|
||||
</h3>
|
||||
{% if token is not empty %}
|
||||
<div class="search import clearfix" id="adminBar">
|
||||
<h3>
|
||||
<img style="margin: 0 5px 0 0; vertical-align: middle; height: 16px" width="16" height="16" alt="Import" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAADo0lEQVR42u2XS0hUURjHD5njA1oYbXQ2MqCmIu2iEEISUREEEURxFB8ovt+DEsLgaxBRQQeUxnQ0ZRYSQasgiDaFqxAy2jUtCjdCoEjFwHj6/+F+dbvN6PQAN37wm++c7/z/35x7uPcOo7TW58rFBs59A7GGQ51XBAIBlZmZuYOhE1zm/A/4PxvY3NwMO53OYEJCgp+nccqXXQc94D54boAxalyLNayNtra2NJmbmzvOyMj4cRqoKYK4AsZzc3Nft7e3f5qZmTnCpk8Ix6xxjRpDGzmkUU5Ozuu2trZP09PTR+vr6ycbGxtaWFtbC9fU1AQTExPdmNNzLSUlZXt4ePhANNGghlp6lDWkkcvlOsCX6LNYXV0N8BTS0tK2cDJfWIsFaumhV0lIIxzXl5WVFX0aPp8vhDwJbMnJyc6JiYkji8YP7oI4YowfmDX00KskOHG73UfLy8vahB/cBXFSW1pa2kPOA7RdqqysfGtaCyOXA2VGgmvUiJ5e9lD8qKioeOv1ejVZXFwMI5eLEWOFWgh5Etg4J0lJSTdwYiHxLSwseFi3Yg5qRE8veyh+TE1Nhebn5zWZnZ31mE2okTxmM6WlpS7xeDyeQ2Qb61bMQQ214mMPVVxc7MJuNBkfHz9EtplNmEcET4JPfL29va+i6azR19f3UnzV1dUrqqqqyocT0KSzs/OV1YB6ROrr67fF19TU9DSazhp1dXXPxdfS0vJQNTY2+sfGxjSpra19YTWgHhHs/pn40OhRNJ0lLuON+kF8ra2tY9yAe3R0VBMc6wfr84n6b1BDrfiam5snImgczObAq7ylv7//q/hGRkbuqMHBwTt4Q2nS3d39jSKzCfXfoKarq+ur+NhD1owLcNrt9h3OTXGrqKgoKJ6hoaFD5DhuIA43xiGyJoWFhUGKxYXaL3CNGtH39PR8Zg9jzREfH+8vKCgI4krDRu0GcGVnZ78ZGBg4ER/Wf+4OVzOMRhrwFE6ysrLe0EQzaopII65RI3p478lVp6am7uDmPJY11F44HI7dsrKyfc5Nnj1km5Lo6Oiw4cdnD1kLJSUl++np6btsQjhmzayB5x29uGp3fn5+EPMw66eBX8b3yHZlDdyRdtzN75F1LED7kR6gMA7E6HsMrqpogbv5KngM9Bk8MbTKwAYmQSiCdhd4wW0VazQ0NNwEXrALNDHGS+A2UFHIA3smj/rX4JvrT7GBSRDi/J8Db8e/JY/5jLj4Y3KxgfPfwHc53iL+IQDMOgAAAABJRU5ErkJggg==">
|
||||
Admin
|
||||
</h3>
|
||||
|
||||
<form action="{{ path('_profiler_import') }}" method="post" enctype="multipart/form-data">
|
||||
{% if token is not empty %}
|
||||
<div style="margin-bottom: 10px">
|
||||
» <a href="{{ path('_profiler_purge', { 'token': token }) }}">Purge</a>
|
||||
</div>
|
||||
<div style="margin-bottom: 10px">
|
||||
» <a href="{{ path('_profiler_export', { 'token': token }) }}">Export</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
» <label for="file">Import</label><br>
|
||||
<input type="file" name="file" id="file"><br>
|
||||
<button type="submit" class="sf-button">
|
||||
<span class="border-l">
|
||||
<span class="border-r">
|
||||
<span class="btn-bg">UPLOAD</span>
|
||||
</span>
|
||||
</span>
|
||||
</button>
|
||||
<div class="clear-fix"></div>
|
||||
</form>
|
||||
</div>
|
||||
<div style="margin-bottom: 10px">» <a href="{{ path('_profiler_purge', { 'token': token }) }}">Purge</a></div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Bundle\WebProfilerBundle\Tests\Command;
|
||||
|
||||
use Symfony\Bundle\WebProfilerBundle\Command\ExportCommand;
|
||||
use Symfony\Component\Console\Tester\CommandTester;
|
||||
use Symfony\Component\Console\Application;
|
||||
use Symfony\Component\HttpKernel\Profiler\Profile;
|
||||
|
||||
class ExportCommandTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
/**
|
||||
* @expectedException \LogicException
|
||||
*/
|
||||
public function testExecuteWithUnknownToken()
|
||||
{
|
||||
$profiler = $this
|
||||
->getMockBuilder('Symfony\Component\HttpKernel\Profiler\Profiler')
|
||||
->disableOriginalConstructor()
|
||||
->getMock()
|
||||
;
|
||||
|
||||
$command = new ExportCommand($profiler);
|
||||
$commandTester = new CommandTester($command);
|
||||
$commandTester->execute(array('token' => 'TOKEN'));
|
||||
}
|
||||
|
||||
public function testExecuteWithToken()
|
||||
{
|
||||
$profiler = $this
|
||||
->getMockBuilder('Symfony\Component\HttpKernel\Profiler\Profiler')
|
||||
->disableOriginalConstructor()
|
||||
->getMock()
|
||||
;
|
||||
|
||||
$profile = new Profile('TOKEN');
|
||||
$profiler->expects($this->once())->method('loadProfile')->with('TOKEN')->will($this->returnValue($profile));
|
||||
|
||||
$command = new ExportCommand($profiler);
|
||||
$commandTester = new CommandTester($command);
|
||||
$commandTester->execute(array('token' => 'TOKEN'));
|
||||
$this->assertEquals($profiler->export($profile), $commandTester->getDisplay());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Bundle\WebProfilerBundle\Tests\Command;
|
||||
|
||||
use Symfony\Bundle\WebProfilerBundle\Command\ImportCommand;
|
||||
use Symfony\Component\Console\Tester\CommandTester;
|
||||
use Symfony\Component\Console\Application;
|
||||
use Symfony\Component\HttpKernel\Profiler\Profile;
|
||||
|
||||
class ImportCommandTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
public function testExecute()
|
||||
{
|
||||
$profiler = $this
|
||||
->getMockBuilder('Symfony\Component\HttpKernel\Profiler\Profiler')
|
||||
->disableOriginalConstructor()
|
||||
->getMock()
|
||||
;
|
||||
|
||||
$profiler->expects($this->once())->method('import')->will($this->returnValue(new Profile('TOKEN')));
|
||||
|
||||
$command = new ImportCommand($profiler);
|
||||
$commandTester = new CommandTester($command);
|
||||
$commandTester->execute(array('filename' => __DIR__.'/../Fixtures/profile.data'));
|
||||
$this->assertRegExp('/Profile "TOKEN" has been successfully imported\./', $commandTester->getDisplay());
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
Tzo0NToiU3ltZm9ueVxDb21wb25lbnRcSHR0cEtlcm5lbFxQcm9maWxlclxQcm9maWxlIjo4OntzOjUyOiIAU3ltZm9ueVxDb21wb25lbnRcSHR0cEtlcm5lbFxQcm9maWxlclxQcm9maWxlAHRva2VuIjtzOjU6IlRPS0VOIjtzOjUzOiIAU3ltZm9ueVxDb21wb25lbnRcSHR0cEtlcm5lbFxQcm9maWxlclxQcm9maWxlAHBhcmVudCI7TjtzOjU1OiIAU3ltZm9ueVxDb21wb25lbnRcSHR0cEtlcm5lbFxQcm9maWxlclxQcm9maWxlAGNoaWxkcmVuIjthOjA6e31zOjU3OiIAU3ltZm9ueVxDb21wb25lbnRcSHR0cEtlcm5lbFxQcm9maWxlclxQcm9maWxlAGNvbGxlY3RvcnMiO2E6MDp7fXM6NDk6IgBTeW1mb255XENvbXBvbmVudFxIdHRwS2VybmVsXFByb2ZpbGVyXFByb2ZpbGUAaXAiO047czo1MzoiAFN5bWZvbnlcQ29tcG9uZW50XEh0dHBLZXJuZWxcUHJvZmlsZXJcUHJvZmlsZQBtZXRob2QiO047czo1MDoiAFN5bWZvbnlcQ29tcG9uZW50XEh0dHBLZXJuZWxcUHJvZmlsZXJcUHJvZmlsZQB1cmwiO047czo1MToiAFN5bWZvbnlcQ29tcG9uZW50XEh0dHBLZXJuZWxcUHJvZmlsZXJcUHJvZmlsZQB0aW1lIjtOO30=
|
Reference in New Issue