Skip to content

Commit eba8e58

Browse files
committed
Merge pull request #34 from phpcr/import_file
Added ability to import a file into the repository
2 parents 586b757 + f787b82 commit eba8e58

File tree

6 files changed

+212
-2
lines changed

6 files changed

+212
-2
lines changed

CHANGELOG.md

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,10 @@
11
# alpha2 / dev-master
22

3-
- Added `--pretty` option to `session:export:view` command to output formatted XML
4-
- Ask confirmation before overwriting file in `session:export:view`
3+
## Features
4+
5+
- New command: `file:import`: - import files into the repository.
6+
7+
## Improvements
8+
9+
- `session:export:view`: Added `--pretty` option to `session:export:view` command to output formatted XML.
10+
- `session:export:view`: Ask confirmation before overwriting file.

features/bootstrap/FeatureContext.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -471,6 +471,15 @@ public function thereExistsAPropertyAt($arg1)
471471
$session->getProperty($arg1);
472472
}
473473

474+
/**
475+
* @Given /^there should exist a property at "([^"]*)"$/
476+
*/
477+
public function thereShouldExistAPropertyAt($arg1)
478+
{
479+
$session = $this->getSession();
480+
$session->getProperty($arg1);
481+
}
482+
474483
/**
475484
* @Given /^there should not exist a property at "([^"]*)"$/
476485
*/
19.1 KB
Loading

features/phpcr_file_import.feature

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
Feature: Import an external file as to a node
2+
In order to import an external file into the system
3+
As a user that is logged into the shell
4+
I should be able to run a command which does that
5+
6+
Background:
7+
Given that I am logged in as "testuser"
8+
And the "cms.xml" fixtures are loaded
9+
And the file "phpcr.png" contains the contents of "files/phpcrlogos.png"
10+
And the current node is "/"
11+
12+
Scenario: Import a file
13+
Given I execute the "file:import . phpcr.png" command
14+
Then the command should not fail
15+
And I save the session
16+
Then the command should not fail
17+
And there should exist a node at "/phpcr.png"
18+
And the node at "/phpcr.png/jcr:content" should have the property "jcr:mimeType" with value "image/png"
19+
20+
Scenario: Import a file onto existing file, no overwrite specified
21+
Given I execute the "file:import . phpcr.png" command
22+
And I execute the "file:import . phpcr.png" command
23+
Then the command should fail
24+
25+
Scenario: Import a file onto existing file, force not specified
26+
Given I execute the "file:import . phpcr.png --no-interaction" command
27+
And I execute the "file:import . phpcr.png" command
28+
Then the command should fail
29+
30+
Scenario: Import a file onto existing file, force specified
31+
Given I execute the "file:import . phpcr.png" command
32+
And I execute the "file:import . phpcr.png --force" command
33+
Then the command should not fail
34+
And I save the session
35+
Then the command should not fail
36+
And there should exist a node at "/phpcr.png"
37+
And the node at "/phpcr.png/jcr:content" should have the property "jcr:mimeType" with value "image/png"
38+
39+
Scenario: Import a file, override mime type
40+
Given I execute the "file:import . phpcr.png --mime-type=application/data" command
41+
Then the command should not fail
42+
And I save the session
43+
Then the command should not fail
44+
And there should exist a node at "/phpcr.png"
45+
And the node at "/phpcr.png/jcr:content" should have the property "jcr:mimeType" with value "application/data"
46+
47+
Scenario: Import a file, specify a name
48+
Given I execute the "file:import ./foobar.png phpcr.png --mime-type=application/data" command
49+
Then the command should not fail
50+
And I save the session
51+
Then the command should not fail
52+
And there should exist a node at "/foobar.png"
53+
54+
Scenario: Import a file to a specified property
55+
Given I execute the "file:import ./ phpcr.png --no-container" command
56+
Then the command should not fail
57+
And I save the session
58+
Then the command should not fail
59+
And there should exist a property at "/phpcr.png"
60+
61+
Scenario: Import overwrite a specified property
62+
Given I execute the "file:import ./ phpcr.png --no-container" command
63+
And I save the session
64+
And I execute the "file:import ./ phpcr.png --no-container" command
65+
Then the command should not fail
66+
And I save the session
67+
Then the command should not fail
68+
And there should exist a property at "/phpcr.png"

src/PHPCR/Shell/Console/Application/ShellApplication.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,7 @@ private function registerCommands()
189189
$this->add(new CommandPhpcr\NodeCreateCommand());
190190
$this->add(new CommandPhpcr\NodeCorrespondingCommand());
191191
$this->add(new CommandPhpcr\NodeDefinitionCommand());
192+
$this->add(new CommandPhpcr\NodeFileImportCommand());
192193
$this->add(new CommandPhpcr\NodePropertySetCommand());
193194
$this->add(new CommandPhpcr\NodeSetPrimaryTypeCommand());
194195
$this->add(new CommandPhpcr\NodeRenameCommand());
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
<?php
2+
3+
namespace PHPCR\Shell\Console\Command\Phpcr;
4+
5+
use Symfony\Component\Console\Command\Command;
6+
use Symfony\Component\Console\Input\InputInterface;
7+
use Symfony\Component\Console\Output\OutputInterface;
8+
use Symfony\Component\Console\Input\InputArgument;
9+
use PHPCR\PropertyType;
10+
use Symfony\Component\Console\Input\InputOption;
11+
use PHPCR\PathNotFoundException;
12+
13+
class NodeFileImportCommand extends Command
14+
{
15+
/**
16+
* @var PHPCR\SessionInterface
17+
*/
18+
protected $session;
19+
20+
protected function configure()
21+
{
22+
$this->setName('file:import');
23+
$this->setDescription('Import a file at the given path');
24+
$this->addArgument('path', InputArgument::REQUIRED, 'Path to import file to');
25+
$this->addArgument('file', InputArgument::REQUIRED, 'Path to file to import');
26+
$this->addOption('mime-type', null, InputOption::VALUE_REQUIRED, 'Mime type (optional, auto-detected)');
27+
$this->addOption('force', null, InputOption::VALUE_NONE, 'Force overwriting any existing node');
28+
$this->addOption('no-container', null, InputOption::VALUE_NONE, 'Do not wrap in a JCR nt:file, but write directly to the specified property');
29+
$this->setHelp(<<<HERE
30+
Import an external file into the repository.
31+
32+
The file will be imported as a node of built-in type <comment>nt:file</comment>.
33+
34+
If a Node is specified as <info>path</info> then the filename of the imported file will be used
35+
as the new node, otherwise, if the target <info>path</info> does not exist, then it is assumed
36+
that the path is the target path for the new file, including the filename.
37+
38+
PHPCRSH> file:import ./ foobar.png
39+
PHPCRSH> file:import ./barfoo.png foobar.png
40+
41+
In the first example above will create <info>/foobar.png</info>, whereas the second will create
42+
<info>./barfoo.png</info>.
43+
44+
By default the file will be imported in a container, i.e. a node with type <info>nt:file</info>. In
45+
addition to the file data, the node will contain metadata.
46+
47+
Alternatively you can specify the <info>--no-container</info> option to import directly to a single property.
48+
49+
The mime-type of the file (in the case where a container is used) will be automatically determined unless
50+
specified with <info>--mime-type</info>.
51+
HERE
52+
);
53+
}
54+
55+
public function execute(InputInterface $input, OutputInterface $output)
56+
{
57+
$this->session = $this->getHelper('phpcr')->getSession();
58+
59+
$filePath = $input->getArgument('file');
60+
$force = $input->getOption('force');
61+
$noContainer = $input->getOption('no-container');
62+
63+
$path = $this->session->getAbsPath($input->getArgument('path'));
64+
$mimeType = $input->getOption('mime-type');
65+
$filename = basename($filePath);
66+
67+
if (!file_exists($filePath)) {
68+
throw new \InvalidArgumentException(sprintf(
69+
'File "%s" does not exist.',
70+
$filePath
71+
));
72+
}
73+
74+
try {
75+
// first assume the user specified the path to the parent node
76+
$parentNode = $this->session->getNode($path);
77+
} catch (PathNotFoundException $e) {
78+
// if the given path does not exist, assume that the basename is the target
79+
// filename and the dirname the path to the parent node
80+
$parentPath = dirname($path);
81+
$parentNode = $this->session->getNode($parentPath);
82+
$filename = basename($path);
83+
}
84+
85+
$fhandle = fopen($filePath, 'r');
86+
87+
if ($noContainer) {
88+
$this->importToProperty($fhandle, $filePath, $filename, $parentNode, $force);
89+
} else {
90+
$this->importToContainer($fhandle, $mimeType, $filePath, $filename, $parentNode, $force);
91+
}
92+
}
93+
94+
private function importToProperty($fhandle, $filePath, $filename, $parentNode, $force)
95+
{
96+
$parentNode->setProperty($filename, $fhandle, PropertyType::BINARY);
97+
}
98+
99+
private function importToContainer($fhandle, $mimeType, $file, $filename, $parentNode, $force)
100+
{
101+
// if no mime-type specified, guess it.
102+
if (!$mimeType) {
103+
$finfo = finfo_open(FILEINFO_MIME_TYPE);
104+
$mimeType = finfo_file($finfo, $file);
105+
}
106+
107+
// handle existing node
108+
if ($parentNode->hasNode($filename)) {
109+
if (true === $force) {
110+
$fileNode = $parentNode->getNode($filename);
111+
$this->session->removeItem($fileNode->getPath());
112+
} else {
113+
throw new \InvalidArgumentException(sprintf(
114+
'Node "%s" already has child "%s". Use --force to overwrite.',
115+
$parentNode->getPath(),
116+
$filename
117+
));
118+
}
119+
}
120+
121+
$fileNode = $parentNode->addNode($filename, 'nt:file');
122+
$contentNode = $fileNode->addNode('jcr:content', 'nt:unstructured');
123+
$contentNode->setProperty('jcr:data', $fhandle, PropertyType::BINARY);
124+
$contentNode->setProperty('jcr:mimeType', $mimeType);
125+
}
126+
}

0 commit comments

Comments
 (0)