1010use Jackalope \Query \QOM \PropertyValue ;
1111use PHPCR \Query \QOM \QueryObjectModelConstantsInterface ;
1212use PHPCR \Query \QOM \LiteralInterface ;
13+ use PHPCR \Shell \Query \UpdateProcessor ;
1314
1415class QueryUpdateCommand extends Command
1516{
@@ -24,23 +25,30 @@ protected function configure()
2425 $ this ->setDescription ('Execute an UPDATE JCR-SQL2 query ' );
2526 $ this ->addArgument ('query ' );
2627 $ this ->setHelp (<<<EOT
27- Execute a JCR-SQL2 update query. Unlike other commands you can enter a query literally:
28+ Execute a PHPCR-Shell JCR-SQL2 update query. You can enter a query literally:
2829
2930 UPDATE [nt:unstructured] AS a SET title = 'foobar' WHERE a.title = 'barfoo';
3031
31- You can update multivalue properties too :
32+ You can also manipulate multivalue fields :
3233
33- # Add a property
34- UPDATE [nt:unstructured] AS a SET a.tags[] = 'foo'
35-
36- # Set values
37- UPDATE [nt:unstructured] AS a SET a.tags = ['one', 'two', 'three', 'four']
38-
3934 # Delete index
4035 UPDATE [nt:unstructured] SET a.tags[0] = NULL
4136
42- # Update a multivalue index by value
43- UPDATE [nt:unstructured] SET a.tags = 'Foo' WHERE a.tags = 'Bar';
37+ # Set index
38+ UPDATE [nt:unstructured] SET a.tags[0] = 'foo'
39+
40+ And you have access to a set of functions when assigning a value:
41+
42+ # Replace the multivalue value "Planes" with "Trains"
43+ UPDATE [nt:unstructured] AS a SET a.tags[] = array_replace(a.tags, 'Planes', 'Trains')
44+
45+ # Append a multivalue
46+ UPDATE [nt:unstructured] AS a SET a.tags = array_append(a.tags, 'Rockets')
47+
48+ # Remove by value
49+ UPDATE [nt:unstructured] AS a SET a.tags = array_remove(a.tags, 'Plains')
50+
51+ Refer to the documentation for a full reference: http://phpcr.readthedocs.org/en/latest/phpcr-shell
4452
4553You must call <info>session:save</info> to persist changes.
4654
@@ -67,130 +75,22 @@ public function execute(InputInterface $input, OutputInterface $output)
6775 $ res = $ updateParser ->parse ($ sql );
6876 $ query = $ res ->offsetGet (0 );
6977 $ updates = $ res ->offsetGet (1 );
70- $ constraint = $ res ->offsetGet (2 );
7178
7279 $ start = microtime (true );
7380 $ result = $ query ->execute ();
7481 $ rows = 0 ;
7582
83+ $ updateProcessor = new UpdateProcessor ();
84+
7685 foreach ($ result as $ row ) {
7786 $ rows ++;
7887 foreach ($ updates as $ property ) {
79- $ node = $ row ->getNode ($ property ['selector ' ]);
80-
81- if ($ node ->hasProperty ($ property ['name ' ])) {
82- $ value = $ this ->handleMultiValue ($ node , $ property , $ constraint );
83- } else {
84- $ value = $ property ['value ' ];
85- }
86-
87- $ node ->setProperty ($ property ['name ' ], $ value );
88+ $ updateProcessor ->updateNode ($ row , $ property );
8889 }
8990 }
9091
9192 $ elapsed = microtime (true ) - $ start ;
9293
9394 $ output ->writeln (sprintf ('%s row(s) affected in %ss ' , $ rows , number_format ($ elapsed , 2 )));
9495 }
95-
96- protected function handleMultiValue ($ node , $ propertyData , $ constraint )
97- {
98- $ phpcrProperty = $ node ->getProperty ($ propertyData ['name ' ]);
99- $ value = $ propertyData ['value ' ];
100-
101- if (false === $ phpcrProperty ->isMultiple ()) {
102- return $ value ;
103- }
104-
105- $ currentValue = $ phpcrProperty ->getValue ();
106-
107- // there is an array operator ([] or [x])
108- if (isset ($ propertyData ['array_op ' ])) {
109- $ arrayOp = $ propertyData ['array_op ' ];
110- if ($ arrayOp === UpdateParser::ARRAY_OPERATION_ADD ) {
111- foreach ((array ) $ value as $ v ) {
112- $ currentValue [] = $ v ;
113- }
114-
115- return $ currentValue ;
116- } elseif ($ arrayOp === UpdateParser::ARRAY_OPERATION_SUB ) {
117- $ arrayIndex = $ propertyData ['array_index ' ];
118-
119- if (!isset ($ currentValue [$ arrayIndex ])) {
120- throw new \InvalidArgumentException (sprintf (
121- 'Multivalue index "%s" does not exist in multivalue field "%s" ' , $ arrayIndex , $ propertyData ['name ' ]
122- ));
123- }
124-
125- if (null === $ value ) {
126- unset($ currentValue [$ arrayIndex ]);
127- return array_values ($ currentValue );
128- }
129-
130- if (is_array ($ value )) {
131- throw new \InvalidArgumentException (sprintf ('Cannot set index to array value on "%s" ' , $ propertyData ['name ' ]));
132- }
133-
134- $ currentValue [$ arrayIndex ] = $ value ;
135-
136- return $ currentValue ;
137- }
138- }
139-
140- if (is_array ($ value )) {
141- return $ value ;
142- }
143-
144- if ($ constraint instanceof ComparisonConstraint) {
145-
146- $ op1 = $ constraint ->getOperand1 ();
147- $ op2 = $ constraint ->getOperand2 ();
148- $ operator = $ constraint ->getOperator ();
149- if ($ op1 instanceOf PropertyValue) {
150- if (
151- ($ propertyData ['selector ' ] === null ||
152- $ op1 ->getSelectorName () == $ propertyData ['selector ' ]) &&
153- $ op1 ->getPropertyName () == $ propertyData ['name ' ]
154- )
155- {
156- if ($ operator !== QueryObjectModelConstantsInterface::JCR_OPERATOR_EQUAL_TO ) {
157- throw new \InvalidArgumentException (sprintf (
158- 'You must use the "=" operator in the comparison when specifying a specific multiple value update '
159- ));
160- }
161-
162- if (!$ op2 instanceof LiteralInterface) {
163- throw new \InvalidArgumentException (sprintf (
164- 'The value of "%s" must be a literal ' , $ propertyData ['name ' ]
165- ));
166- }
167-
168- $ targetValue = $ op2 ->getLiteralValue ();
169-
170- foreach ($ currentValue as $ k => $ v ) {
171- if ($ v === $ targetValue ) {
172- if (null === $ value ) {
173- unset($ currentValue [$ k ]);
174- $ currentValue = array_values ($ currentValue );
175- } else {
176- $ currentValue [$ k ] = $ value ;
177- }
178- }
179- }
180-
181- return $ currentValue ;
182- }
183- }
184- }
185-
186- // do not allow updating multivalue with scalar
187- if (false === is_array ($ value ) && sizeof ($ currentValue ) > 1 ) {
188- throw new \InvalidArgumentException (sprintf (
189- '<error>Cannot update multivalue property "%s" with a scalar value.</error> ' ,
190- $ phpcrProperty ->getName ()
191- ));
192- }
193-
194- return $ value ;
195- }
19696}
0 commit comments