Completed
Branch master (c3c77b)
by Aimeos
03:13
created

Standard::getContainer()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 86
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 6
nc 1
nop 0
dl 0
loc 86
rs 10
c 0
b 0
f 0

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
/**
4
 * @license LGPLv3, http://opensource.org/licenses/LGPL-3.0
5
 * @copyright Aimeos (aimeos.org), 2017-2018
6
 * @package Controller
7
 * @subpackage Jobs
8
 */
9
10
11
namespace Aimeos\Controller\Jobs\Order\Export\Csv;
12
13
14
/**
15
 * Job controller for CSV order exports.
16
 *
17
 * @package Controller
18
 * @subpackage Jobs
19
 */
20
class Standard
21
	extends \Aimeos\Controller\Jobs\Order\Export\Csv\Base
22
	implements \Aimeos\Controller\Jobs\Iface
23
{
24
	/**
25
	 * Returns the localized name of the job.
26
	 *
27
	 * @return string Name of the job
28
	 */
29
	public function getName()
30
	{
31
		return $this->getContext()->getI18n()->dt( 'controller/jobs', 'Order export CSV' );
32
	}
33
34
35
	/**
36
	 * Returns the localized description of the job.
37
	 *
38
	 * @return string Description of the job
39
	 */
40
	public function getDescription()
41
	{
42
		return $this->getContext()->getI18n()->dt( 'controller/jobs', 'Exports orders to CSV file' );
43
	}
44
45
46
	/**
47
	 * Executes the job.
48
	 *
49
	 * @throws \Aimeos\Controller\Jobs\Exception If an error occurs
50
	 */
51
	public function run()
52
	{
53
		$context = $this->getContext();
54
		$config = $context->getConfig();
55
		$logger = $context->getLogger();
56
		$mappings = $this->getDefaultMapping();
57
58
59
		/** controller/common/order/export/csv/mapping
60
		 * List of mappings between the position in the CSV file and item keys
61
		 *
62
		 * The exporter has to know which data is at which position in the CSV
63
		 * file. Therefore, you need to specify a mapping between each position
64
		 * and the MShop domain item key (e.g. "order.type") it represents.
65
		 *
66
		 * These mappings are grouped together by their processor names, which
67
		 * are responsible for exporting the data, e.g. all mappings in "invoice"
68
		 * will be managed by the invoice processor while the mappings in
69
		 * "product" will be exported by the product processor.
70
		 *
71
		 * @param array Associative list of processor names and lists of key/position pairs
72
		 * @since 2017.08
73
		 * @category Developer
74
		 * @see controller/common/order/export/csv/max-size
75
		 */
76
		$mappings = $config->get( 'controller/common/order/export/csv/mapping', $mappings );
77
78
		/** controller/jobs/order/export/csv/mapping
79
		 * List of mappings between the position in the CSV file and item keys
80
		 *
81
		 * This configuration setting overwrites the shared option
82
		 * "controller/common/order/export/csv/mapping" if you need a
83
		 * specific setting for the job controller. Otherwise, you should
84
		 * use the shared option for consistency.
85
		 *
86
		 * @param array Associative list of processor names and lists of key/position pairs
87
		 * @since 2017.08
88
		 * @category Developer
89
		 * @see controller/common/order/export/csv/max-size
90
		 */
91
		$mappings = $config->get( 'controller/jobs/order/export/csv/mapping', $mappings );
92
93
94
		/** controller/common/order/export/csv/max-size
95
		 * Maximum number of CSV rows to export at once
96
		 *
97
		 * It's more efficient to read and export more than one row at a time
98
		 * to speed up the export. Usually, the bigger the chunk that is exported
99
		 * at once, the less time the exporter will need. The downside is that
100
		 * the amount of memory required by the export process will increase as
101
		 * well. Therefore, it's a trade-off between memory consumption and
102
		 * export speed.
103
		 *
104
		 * @param integer Number of rows
105
		 * @since 2017.08
106
		 * @category Developer
107
		 * @see controller/common/order/export/csv/mapping
108
		 */
109
		$maxcnt = (int) $config->get( 'controller/common/order/export/csv/max-size', 1000 );
110
111
112
		$processors = $this->getProcessors( $mappings );
113
		$mq = $context->getMessageQueueManager()->get( 'mq-admin' )->getQueue( 'order-export' );
114
115
		while( ( $msg = $mq->get() ) !== null )
116
		{
117
			try
118
			{
119
				if( ( $data = json_decode( $msg->getBody(), true ) ) === null ) {
120
					throw new \Aimeos\Controller\Jobs\Exception( sprintf( 'Invalid message: %1$s', $msg->getBody() ) );
121
				}
122
123
				$this->export( $processors, $data, $maxcnt );
0 ignored issues
show
Bug introduced by
$processors of type Aimeos\Controller\Common...ort\Csv\Processor\Iface is incompatible with the type array expected by parameter $processors of Aimeos\Controller\Jobs\O...\Csv\Standard::export(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

123
				$this->export( /** @scrutinizer ignore-type */ $processors, $data, $maxcnt );
Loading history...
124
			}
125
			catch( \Exception $e )
126
			{
127
				$logger->log( 'Order export error: ' . $e->getMessage() );
128
				$logger->log( $e->getTraceAsString() );
129
			}
130
131
			$mq->del( $msg );
132
		}
133
	}
134
135
136
	/**
137
	 * Creates a new job entry for the exported file
138
	 *
139
	 * @param \Aimeos\MShop\Context\Item\Iface $context Context item
140
	 * @param string $path Absolute path to the exported file
141
	 */
142
	protected function addJob( $context, $path )
143
	{
144
		$manager = \Aimeos\MAdmin::create( $context, 'job' );
145
146
		$item = $manager->createItem();
147
		$item->setResult( ['file' => $path] );
0 ignored issues
show
Bug introduced by
The method setResult() does not exist on Aimeos\MShop\Attribute\Item\Iface. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

147
		$item->/** @scrutinizer ignore-call */ 
148
         setResult( ['file' => $path] );

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
148
		$item->setLabel( $path );
149
150
		$manager->saveItem( $item, false );
151
	}
152
153
154
	/**
155
	 * Opens and returns the container which includes the order data
156
	 *
157
	 * @return \Aimeos\MW\Container\Iface Container object
158
	 */
159
	protected function getContainer()
160
	{
161
		$config = $this->getContext()->getConfig();
162
163
		/** controller/jobs/order/export/csv/location
164
		 * Temporary file or directory where the content is stored which should be exported
165
		 *
166
		 * The path can point to any supported container format as long as the
167
		 * content is in CSV format, e.g.
168
		 * * Directory container / CSV file
169
		 * * Zip container / compressed CSV file
170
		 * * PHPExcel container / PHPExcel sheet
171
		 *
172
		 * @param string Absolute file or directory path
173
		 * @since 2017.08
174
		 * @category Developer
175
		 * @category User
176
		 * @see controller/jobs/order/export/csv/container/type
177
		 * @see controller/jobs/order/export/csv/container/content
178
		 * @see controller/jobs/order/export/csv/container/options
179
		 */
180
		$location = $config->get( 'controller/jobs/order/export/csv/location', sys_get_temp_dir() );
181
182
		/** controller/jobs/order/export/csv/container/type
183
		 * Nave of the container type to read the data from
184
		 *
185
		 * The container type tells the exporter how it should retrieve the data.
186
		 * There are currently three container types that support the necessary
187
		 * CSV content:
188
		 * * Directory
189
		 * * Zip
190
		 * * PHPExcel
191
		 *
192
		 * '''Note:''' For the PHPExcel container, you need to install the
193
		 * "ai-container" extension.
194
		 *
195
		 * @param string Container type name
196
		 * @since 2015.05
197
		 * @category Developer
198
		 * @category User
199
		 * @see controller/jobs/order/export/csv/location
200
		 * @see controller/jobs/order/export/csv/container/content
201
		 * @see controller/jobs/order/export/csv/container/options
202
		 */
203
		$container = $config->get( 'controller/jobs/order/export/csv/container/type', 'Directory' );
204
205
		/** controller/jobs/order/export/csv/container/content
206
		 * Name of the content type inside the container to read the data from
207
		 *
208
		 * The content type must always be a CSV-like format and there are
209
		 * currently two format types that are supported:
210
		 * * CSV
211
		 * * PHPExcel
212
		 *
213
		 * '''Note:''' for the PHPExcel content type, you need to install the
214
		 * "ai-container" extension.
215
		 *
216
		 * @param array Content type name
217
		 * @since 2015.05
218
		 * @category Developer
219
		 * @category User
220
		 * @see controller/jobs/order/export/csv/location
221
		 * @see controller/jobs/order/export/csv/container/type
222
		 * @see controller/jobs/order/export/csv/container/options
223
		 */
224
		$content = $config->get( 'controller/jobs/order/export/csv/container/content', 'CSV' );
225
226
		/** controller/jobs/order/export/csv/container/options
227
		 * List of file container options for the order export files
228
		 *
229
		 * Some container/content type allow you to hand over additional settings
230
		 * for configuration. Please have a look at the article about
231
		 * {@link http://aimeos.org/docs/Developers/Utility/Create_and_read_files container/content files}
232
		 * for more information.
233
		 *
234
		 * @param array Associative list of option name/value pairs
235
		 * @since 2015.05
236
		 * @category Developer
237
		 * @category User
238
		 * @see controller/jobs/order/export/csv/location
239
		 * @see controller/jobs/order/export/csv/container/content
240
		 * @see controller/jobs/order/export/csv/container/type
241
		 */
242
		$options = $config->get( 'controller/jobs/order/export/csv/container/options', [] );
243
244
		return \Aimeos\MW\Container\Factory::getContainer( $location, $container, $content, $options );
245
	}
246
247
248
	/**
249
	 * Exports the orders and returns the exported file name
250
	 *
251
	 * @param Aimeos\Controller\Common\Order\Export\Csv\Processor\Iface[] List of processor objects
0 ignored issues
show
Bug introduced by
The type Aimeos\Controller\Jobs\Order\Export\Csv\List was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
252
	 * @param array $msg Message data passed from the frontend
253
	 * @param integer $maxcnt Maximum number of retrieved orders at once
254
	 * @return string Path of the file containing the exported data
255
	 */
256
	protected function export( array $processors, $msg, $maxcnt )
257
	{
258
		$lcontext = $this->getLocaleContext( $msg );
259
		$baseRef = ['order/base/address', 'order/base/coupon', 'order/base/product', 'order/base/service'];
260
261
		$manager = \Aimeos\MShop::create( $lcontext, 'order' );
262
		$baseManager = \Aimeos\MShop::create( $lcontext, 'order/base' );
263
264
		$container = $this->getContainer();
265
		$content = $container->create( 'order-export_' . date( 'Y-m-d_H-i-s' ) );
266
		$search = $this->initCriteria( $manager->createSearch()->setSlice( 0, 0x7fffffff ), $msg );
267
		$start = 0;
268
269
		do
270
		{
271
			$baseIds = [];
272
			$search->setSlice( $start, $maxcnt );
273
			$items = $manager->searchItems( $search );
274
275
			foreach( $items as $item ) {
276
				$baseIds[] = $item->getBaseId();
1 ignored issue
show
Bug introduced by
The method getBaseId() does not exist on Aimeos\MShop\Common\Item\Iface. It seems like you code against a sub-type of Aimeos\MShop\Common\Item\Iface such as Aimeos\MShop\Order\Item\Base\Product\Iface or Aimeos\MShop\Order\Item\Base\Service\Iface or Aimeos\MShop\Order\Item\Base\Coupon\Iface or Aimeos\MShop\Order\Item\Iface or Aimeos\MShop\Order\Item\Base\Service\Base or Aimeos\MShop\Order\Item\Base\Coupon\Standard or Aimeos\MShop\Order\Item\Base\Product\Standard or Aimeos\MShop\Order\Item\Base\Address\Standard or Aimeos\MShop\Order\Item\Standard or Aimeos\MShop\Order\Item\Base\Address\Iface or Aimeos\MShop\Order\Item\Base\Address\Standard. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

276
				/** @scrutinizer ignore-call */ 
277
    $baseIds[] = $item->getBaseId();
Loading history...
277
			}
278
279
			$baseSearch = $baseManager->createSearch();
280
			$baseSearch->setConditions( $baseSearch->compare( '==', 'order.base.id', $baseIds ) );
281
			$baseSearch->setSlice( 0, count( $baseIds ) );
282
283
			$baseItems = $baseManager->searchItems( $baseSearch, $baseRef );
284
285
			foreach( $items as $id => $item )
286
			{
287
				foreach( $processors as $type => $processor )
288
				{
289
					foreach( $processor->process( $item, $baseItems[$item->getBaseId()] ) as $line ) {
290
						$content->add( [0 => $type, 1 => $id] + $line );
291
					}
292
				}
293
			}
294
295
			$count = count( $items );
296
			$start += $count;
297
		}
298
		while( $count === $search->getSliceSize() );
299
300
		$path = $content->getResource();
301
		$container->add( $content );
302
		$container->close();
303
304
		$path = $this->moveFile( $lcontext, $path );
305
		$this->addJob( $lcontext, $path );
306
	}
307
308
309
	/**
310
	 * Returns a new context including the locale from the message data
311
	 *
312
	 * @param array $msg Message data including a "sitecode" value
313
	 * @return \Aimeos\MShop\Context\Item\Iface New context item with updated locale
314
	 */
315
	protected function getLocaleContext( array $msg )
316
	{
317
		$lcontext = clone $this->getContext();
318
		$manager = \Aimeos\MShop::create( $lcontext, 'locale' );
319
320
		$sitecode = ( isset( $msg['sitecode'] ) ? $msg['sitecode'] : 'default' );
321
		$localeItem = $manager->bootstrap( $sitecode, '', '', false, \Aimeos\MShop\Locale\Manager\Base::SITE_PATH );
1 ignored issue
show
Bug introduced by
The method bootstrap() does not exist on Aimeos\MShop\Common\Manager\Iface. It seems like you code against a sub-type of Aimeos\MShop\Common\Manager\Iface such as Aimeos\MShop\Locale\Manager\Iface or Aimeos\MShop\Common\Manager\Decorator\Base or Aimeos\MShop\Service\Manager\Lists\Type\Standard or Aimeos\MShop\Price\Manager\Standard or Aimeos\MShop\Attribute\Manager\Type\Standard or Aimeos\MShop\Price\Manager\Lists\Type\Standard or Aimeos\MShop\Media\Manager\Type\Standard or Aimeos\MShop\Coupon\Manager\Code\Standard or Aimeos\MShop\Order\Manager\Base\Coupon\Standard or Aimeos\MShop\Product\Manager\Standard or Aimeos\MShop\Index\Manager\Standard or Aimeos\MShop\Index\Manager\Attribute\Standard or Aimeos\MShop\Index\Manager\Text\Standard or Aimeos\MShop\Index\Manager\Supplier\Standard or Aimeos\MShop\Index\Manager\Catalog\Standard or Aimeos\MShop\Index\Manager\Price\Standard or Aimeos\MShop\Supplier\Manager\Standard or Aimeos\MShop\Customer\Manager\Property\Standard or Aimeos\MShop\Order\Manager\Base\Service\Standard or Aimeos\MShop\Order\Manager\Base\Standard or Aimeos\MShop\Price\Manager\Lists\Standard or Aimeos\MShop\Supplier\Manager\Lists\Type\Standard or Aimeos\MShop\Order\Manag...vice\Attribute\Standard or Aimeos\MShop\Service\Manager\Lists\Standard or Aimeos\MShop\Tag\Manager\Type\Standard or Aimeos\MShop\Text\Manager\Lists\Standard or Aimeos\MShop\Price\Manager\Type\Standard or Aimeos\MShop\Locale\Manager\Currency\Standard or Aimeos\MShop\Order\Manag...duct\Attribute\Standard or Aimeos\MShop\Media\Manager\Lists\Type\Standard or Aimeos\MShop\Catalog\Manager\Lists\Standard or Aimeos\MShop\Tag\Manager\Standard or Aimeos\MShop\Coupon\Manager\Standard or Aimeos\MShop\Attribute\Manager\Standard or Aimeos\MShop\Attribute\M...\Property\Type\Standard or Aimeos\MShop\Service\Manager\Type\Standard or Aimeos\MShop\Product\Manager\Lists\Standard or Aimeos\MShop\Customer\Ma...\Property\Type\Standard or Aimeos\MShop\Order\Manager\Standard or Aimeos\MShop\Customer\Manager\Standard or Aimeos\MShop\Media\Manager\Standard or Aimeos\MShop\Customer\Manager\Lists\Type\Standard or Aimeos\MShop\Attribute\Manager\Lists\Standard or Aimeos\MShop\Product\Man...\Property\Type\Standard or Aimeos\MShop\Media\Manager\Lists\Standard or Aimeos\MShop\Plugin\Manager\Standard or Aimeos\MShop\Order\Manager\Base\Address\Standard or Aimeos\MShop\Catalog\Manager\Standard or Aimeos\MShop\Locale\Manager\Site\Standard or Aimeos\MShop\Product\Manager\Type\Standard or Aimeos\MShop\Supplier\Manager\Lists\Standard or Aimeos\MShop\Stock\Manager\Type\Standard or Aimeos\MShop\Text\Manager\Standard or Aimeos\MAdmin\Job\Manager\Standard or Aimeos\MShop\Customer\Manager\Group\Standard or Aimeos\MShop\Product\Manager\Lists\Type\Standard or Aimeos\MShop\Text\Manager\Lists\Type\Standard or Aimeos\MShop\Text\Manager\Type\Standard or Aimeos\MShop\Order\Manager\Status\Standard or Aimeos\MShop\Supplier\Manager\Address\Standard or Aimeos\MShop\Customer\Manager\Address\Standard or Aimeos\MShop\Plugin\Manager\Type\Standard or Aimeos\MShop\Stock\Manager\Standard or Aimeos\MShop\Stock\Manager\Nolimit or Aimeos\MShop\Attribute\Manager\Property\Standard or Aimeos\MShop\Subscription\Manager\Standard or Aimeos\MShop\Media\Manager\Property\Type\Standard or Aimeos\MShop\Product\Manager\Property\Standard or Aimeos\MShop\Locale\Manager\Language\Standard or Aimeos\MShop\Media\Manager\Property\Standard or Aimeos\MShop\Service\Manager\Standard or Aimeos\MShop\Attribute\Manager\Lists\Type\Standard or Aimeos\MAdmin\Log\Manager\Standard or Aimeos\MAdmin\Cache\Manager\Standard or Aimeos\MAdmin\Cache\Manager\None or Aimeos\MShop\Order\Manager\Base\Product\Standard or Aimeos\MShop\Customer\Manager\Lists\Standard or Aimeos\MShop\Catalog\Manager\Lists\Type\Standard. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

321
		/** @scrutinizer ignore-call */ 
322
  $localeItem = $manager->bootstrap( $sitecode, '', '', false, \Aimeos\MShop\Locale\Manager\Base::SITE_PATH );
Loading history...
322
323
		return $lcontext->setLocale( $localeItem );
324
	}
325
326
327
	/**
328
	 * Initializes the search criteria
329
	 *
330
	 * @param \Aimeos\MW\Criteria\Iface $criteria New criteria object
331
	 * @param array $msg Message data
332
	 * @return \Aimeos\MW\Criteria\Iface Initialized criteria object
333
	 */
334
	protected function initCriteria( \Aimeos\MW\Criteria\Iface $criteria, array $msg )
335
	{
336
		if( isset( $msg['filter'] ) ) {
337
			$criteria->setConditions( $criteria->toConditions( $msg['filter'] ) );
338
		}
339
340
		if( isset( $msg['sort'] ) ) {
341
			$criteria->setSortations( $criteria->toSortations( $msg['sort'] ) );
342
		}
343
344
		return $criteria;
345
	}
346
347
348
	/**
349
	 * Moves the exported file to the final storage
350
	 *
351
	 * @param \Aimeos\MShop\Context\Item\Iface $context Context item
352
	 * @param string $path Absolute path to the exported file
353
	 * @return string Relative path of the file in the storage
354
	 */
355
	protected function moveFile( $context, $path )
356
	{
357
		$filename = basename( $path );
358
		$context->getFileSystemManager()->get( 'fs-admin' )->writef( $filename, $path );
359
360
		unlink( $path );
361
		return $filename;
362
	}
363
}
364