-
Notifications
You must be signed in to change notification settings - Fork 19
Added ability to import a file into the repository #34
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,10 @@ | ||
# alpha2 / dev-master | ||
|
||
- Added `--pretty` option to `session:export:view` command to output formatted XML | ||
- Ask confirmation before overwriting file in `session:export:view` | ||
## Features | ||
|
||
- New command: `file:import`: - import files into the repository. | ||
|
||
## Improvements | ||
|
||
- `session:export:view`: Added `--pretty` option to `session:export:view` command to output formatted XML. | ||
- `session:export:view`: Ask confirmation before overwriting file. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
Feature: Import an external file as to a node | ||
In order to import an external file into the system | ||
As a user that is logged into the shell | ||
I should be able to run a command which does that | ||
|
||
Background: | ||
Given that I am logged in as "testuser" | ||
And the "cms.xml" fixtures are loaded | ||
And the file "phpcr.png" contains the contents of "files/phpcrlogos.png" | ||
And the current node is "/" | ||
|
||
Scenario: Import a file | ||
Given I execute the "file:import . phpcr.png" command | ||
Then the command should not fail | ||
And I save the session | ||
Then the command should not fail | ||
And there should exist a node at "/phpcr.png" | ||
And the node at "/phpcr.png/jcr:content" should have the property "jcr:mimeType" with value "image/png" | ||
|
||
Scenario: Import a file onto existing file, no overwrite specified | ||
Given I execute the "file:import . phpcr.png" command | ||
And I execute the "file:import . phpcr.png" command | ||
Then the command should fail | ||
|
||
Scenario: Import a file onto existing file, force not specified | ||
Given I execute the "file:import . phpcr.png --no-interaction" command | ||
And I execute the "file:import . phpcr.png" command | ||
Then the command should fail | ||
|
||
Scenario: Import a file onto existing file, force specified | ||
Given I execute the "file:import . phpcr.png" command | ||
And I execute the "file:import . phpcr.png --force" command | ||
Then the command should not fail | ||
And I save the session | ||
Then the command should not fail | ||
And there should exist a node at "/phpcr.png" | ||
And the node at "/phpcr.png/jcr:content" should have the property "jcr:mimeType" with value "image/png" | ||
|
||
Scenario: Import a file, override mime type | ||
Given I execute the "file:import . phpcr.png --mime-type=application/data" command | ||
Then the command should not fail | ||
And I save the session | ||
Then the command should not fail | ||
And there should exist a node at "/phpcr.png" | ||
And the node at "/phpcr.png/jcr:content" should have the property "jcr:mimeType" with value "application/data" | ||
|
||
Scenario: Import a file, specify a name | ||
Given I execute the "file:import ./foobar.png phpcr.png --mime-type=application/data" command | ||
Then the command should not fail | ||
And I save the session | ||
Then the command should not fail | ||
And there should exist a node at "/foobar.png" | ||
|
||
Scenario: Import a file to a specified property | ||
Given I execute the "file:import ./ phpcr.png --no-container" command | ||
Then the command should not fail | ||
And I save the session | ||
Then the command should not fail | ||
And there should exist a property at "/phpcr.png" | ||
|
||
Scenario: Import overwrite a specified property | ||
Given I execute the "file:import ./ phpcr.png --no-container" command | ||
And I save the session | ||
And I execute the "file:import ./ phpcr.png --no-container" command | ||
Then the command should not fail | ||
And I save the session | ||
Then the command should not fail | ||
And there should exist a property at "/phpcr.png" |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,126 @@ | ||
<?php | ||
|
||
namespace PHPCR\Shell\Console\Command\Phpcr; | ||
|
||
use Symfony\Component\Console\Command\Command; | ||
use Symfony\Component\Console\Input\InputInterface; | ||
use Symfony\Component\Console\Output\OutputInterface; | ||
use Symfony\Component\Console\Input\InputArgument; | ||
use PHPCR\PropertyType; | ||
use Symfony\Component\Console\Input\InputOption; | ||
use PHPCR\PathNotFoundException; | ||
|
||
class NodeFileImportCommand extends Command | ||
{ | ||
/** | ||
* @var PHPCR\SessionInterface | ||
*/ | ||
protected $session; | ||
|
||
protected function configure() | ||
{ | ||
$this->setName('file:import'); | ||
$this->setDescription('Import a file at the given path'); | ||
$this->addArgument('path', InputArgument::REQUIRED, 'Path to import file to'); | ||
$this->addArgument('file', InputArgument::REQUIRED, 'Path to file to import'); | ||
$this->addOption('mime-type', null, InputOption::VALUE_REQUIRED, 'Mime type (optional, auto-detected)'); | ||
$this->addOption('force', null, InputOption::VALUE_NONE, 'Force overwriting any existing node'); | ||
$this->addOption('no-container', null, InputOption::VALUE_NONE, 'Do not wrap in a JCR nt:file, but write directly to the specified property'); | ||
$this->setHelp(<<<HERE | ||
Import an external file into the repository. | ||
|
||
The file will be imported as a node of built-in type <comment>nt:file</comment>. | ||
|
||
If a Node is specified as <info>path</info> then the filename of the imported file will be used | ||
as the new node, otherwise, if the target <info>path</info> does not exist, then it is assumed | ||
that the path is the target path for the new file, including the filename. | ||
|
||
PHPCRSH> file:import ./ foobar.png | ||
PHPCRSH> file:import ./barfoo.png foobar.png | ||
|
||
In the first example above will create <info>/foobar.png</info>, whereas the second will create | ||
<info>./barfoo.png</info>. | ||
|
||
By default the file will be imported in a container, i.e. a node with type <info>nt:file</info>. In | ||
addition to the file data, the node will contain metadata. | ||
|
||
Alternatively you can specify the <info>--no-container</info> option to import directly to a single property. | ||
|
||
The mime-type of the file (in the case where a container is used) will be automatically determined unless | ||
specified with <info>--mime-type</info>. | ||
HERE | ||
); | ||
} | ||
|
||
public function execute(InputInterface $input, OutputInterface $output) | ||
{ | ||
$this->session = $this->getHelper('phpcr')->getSession(); | ||
|
||
$filePath = $input->getArgument('file'); | ||
$force = $input->getOption('force'); | ||
$noContainer = $input->getOption('no-container'); | ||
|
||
$path = $this->session->getAbsPath($input->getArgument('path')); | ||
$mimeType = $input->getOption('mime-type'); | ||
$filename = basename($filePath); | ||
|
||
if (!file_exists($filePath)) { | ||
throw new \InvalidArgumentException(sprintf( | ||
'File "%s" does not exist.', | ||
$filePath | ||
)); | ||
} | ||
|
||
try { | ||
// first assume the user specified the path to the parent node | ||
$parentNode = $this->session->getNode($path); | ||
} catch (PathNotFoundException $e) { | ||
// if the given path does not exist, assume that the basename is the target | ||
// filename and the dirname the path to the parent node | ||
$parentPath = dirname($path); | ||
$parentNode = $this->session->getNode($parentPath); | ||
$filename = basename($path); | ||
} | ||
|
||
$fhandle = fopen($filePath, 'r'); | ||
|
||
if ($noContainer) { | ||
$this->importToProperty($fhandle, $filePath, $filename, $parentNode, $force); | ||
} else { | ||
$this->importToContainer($fhandle, $mimeType, $filePath, $filename, $parentNode, $force); | ||
} | ||
} | ||
|
||
private function importToProperty($fhandle, $filePath, $filename, $parentNode, $force) | ||
{ | ||
$parentNode->setProperty($filename, $fhandle, PropertyType::BINARY); | ||
} | ||
|
||
private function importToContainer($fhandle, $mimeType, $file, $filename, $parentNode, $force) | ||
{ | ||
// if no mime-type specified, guess it. | ||
if (!$mimeType) { | ||
$finfo = finfo_open(FILEINFO_MIME_TYPE); | ||
$mimeType = finfo_file($finfo, $file); | ||
} | ||
|
||
// handle existing node | ||
if ($parentNode->hasNode($filename)) { | ||
if (true === $force) { | ||
$fileNode = $parentNode->getNode($filename); | ||
$this->session->removeItem($fileNode->getPath()); | ||
} else { | ||
throw new \InvalidArgumentException(sprintf( | ||
'Node "%s" already has child "%s". Use --force to overwrite.', | ||
$parentNode->getPath(), | ||
$filename | ||
)); | ||
} | ||
} | ||
|
||
$fileNode = $parentNode->addNode($filename, 'nt:file'); | ||
$contentNode = $fileNode->addNode('jcr:content', 'nt:unstructured'); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we could also allow to push a stream into any property of an existing node as an alternative. in some of our projects, we just put a binary stream into a property instead of having the nt:file node. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. hmm. not sure how to elegantly handle that - it would be quite a different behavior (e.g. no node type detection, no wrapping node, etc). Maybe There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. i like the to-property option. a separate command clutters up the list of commands and can be counter-inuitive which to use. --to-property would require the containing node to already exist and create/update the property. |
||
$contentNode->setProperty('jcr:data', $fhandle, PropertyType::BINARY); | ||
$contentNode->setProperty('jcr:mimeType', $mimeType); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i would add an optional nodename in case i don't want the basename of the file i import.