Passed
Push — master ( 88e78d...68cc04 )
by Aimeos
03:20
created

Standard::notify()   A

Complexity

Conditions 4
Paths 8

Size

Total Lines 34
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 18
nc 8
nop 1
dl 0
loc 34
rs 9.6666
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * @license LGPLv3, http://opensource.org/licenses/LGPL-3.0
5
 * @copyright Aimeos (aimeos.org), 2015-2022
6
 * @package Controller
7
 * @subpackage Customer
8
 */
9
10
11
namespace Aimeos\Controller\Jobs\Customer\Email\Watch;
12
13
14
/**
15
 * Product notification e-mail job controller.
16
 *
17
 * @package Controller
18
 * @subpackage Customer
19
 */
20
class Standard
21
	extends \Aimeos\Controller\Jobs\Base
22
	implements \Aimeos\Controller\Jobs\Iface
23
{
24
	use \Aimeos\Controller\Jobs\Mail;
25
26
27
	/**
28
	 * Returns the localized name of the job.
29
	 *
30
	 * @return string Name of the job
31
	 */
32
	public function getName() : string
33
	{
34
		return $this->context()->translate( 'controller/jobs', 'Product notification e-mails' );
35
	}
36
37
38
	/**
39
	 * Returns the localized description of the job.
40
	 *
41
	 * @return string Description of the job
42
	 */
43
	public function getDescription() : string
44
	{
45
		return $this->context()->translate( 'controller/jobs', 'Sends e-mails for watched products' );
46
	}
47
48
49
	/**
50
	 * Executes the job.
51
	 *
52
	 * @throws \Aimeos\Controller\Jobs\Exception If an error occurs
53
	 */
54
	public function run()
55
	{
56
		$manager = \Aimeos\MShop::create( $this->context(), 'customer' );
57
58
		$search = $manager->filter( true );
59
		$func = $search->make( 'customer:has', ['product', 'watch'] );
60
		$search->add( $search->is( $func, '!=', null ) )->order( 'customer.id' );
61
62
		$start = 0;
63
64
		do
65
		{
66
			$customers = $manager->search( $search->slice( $start ), ['product' => ['watch']] );
67
			$customers = $this->notify( $customers );
68
			$customers = $manager->save( $customers );
69
70
			$count = count( $customers );
0 ignored issues
show
Bug introduced by
It seems like $customers can also be of type Aimeos\MShop\Common\Item\Iface; however, parameter $value of count() does only seem to accept Countable|array, maybe add an additional type check? ( Ignorable by Annotation )

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

70
			$count = count( /** @scrutinizer ignore-type */ $customers );
Loading history...
71
			$start += $count;
72
		}
73
		while( $count >= $search->getLimit() );
74
	}
75
76
77
	/**
78
	 * Sends product notifications for the given customers in their language
79
	 *
80
	 * @param \Aimeos\Map $customers List of customer items implementing \Aimeos\MShop\Customer\Item\Iface
81
	 * @return \Aimeos\Map List of customer items implementing \Aimeos\MShop\Customer\Item\Iface
82
	 */
83
	protected function notify( \Aimeos\Map $customers ) : \Aimeos\Map
84
	{
85
		$context = $this->context();
86
		$date = date( 'Y-m-d H:i:s' );
87
88
		foreach( $customers as $customer )
89
		{
90
			$listItems = $customer->getListItems( 'product', null, null, false );
91
			$products = $this->products( $listItems );
92
93
			try
94
			{
95
				if( !empty( $products ) ) {
96
					$this->send( $customer, $products );
97
				}
98
99
				$str = sprintf( 'Sent product notification e-mail to "%1$s"', $customer->getPaymentAddress()->getEmail() );
100
				$context->logger()->debug( $str, 'email/customer/watch' );
101
			}
102
			catch( \Exception $e )
103
			{
104
				$str = 'Error while trying to send product notification e-mail for customer ID "%1$s": %2$s';
105
				$msg = sprintf( $str, $customer->getId(), $e->getMessage() ) . PHP_EOL . $e->getTraceAsString();
106
				$context->logger()->error( $msg, 'email/customer/watch' );
107
			}
108
109
			$remove = $listItems->diffKeys( $products )->filter( function( $listItem ) use ( $date ) {
110
				return $listItem->getDateEnd() < $date;
111
			} );
112
113
			$customer->deleteListItems( $remove );
114
		}
115
116
		return $customers;
117
	}
118
119
120
	/**
121
	 * Returns a filtered list of products for which a notification should be sent
122
	 *
123
	 * @param \Aimeos\Map $listItems List of customer list items
124
	 * @return array Associative list of list IDs as key and product items values
125
	 */
126
	protected function products( \Aimeos\Map $listItems ) : array
127
	{
128
		$priceManager = \Aimeos\MShop::create( $this->context(), 'price' );
129
		$result = [];
130
131
		foreach( $listItems as $id => $listItem )
132
		{
133
			try
134
			{
135
				if( $product = $listItem->getRefItem() )
136
				{
137
					$config = $listItem->getConfig();
138
					$prices = $product->getRefItems( 'price', 'default', 'default' );
139
					$price = $priceManager->getLowestPrice( $prices, 1, $config['currency'] ?? null );
140
141
					if( $config['stock'] ?? null || $config['price'] ?? null
142
						&& $product->inStock() && ( $config['pricevalue'] ?? 0 ) > $price->getValue()
143
					) {
144
						$result[$id] = $product->set( 'price', $price );
145
					}
146
				}
147
			}
148
			catch( \Exception $e ) { ; } // no price available
149
		}
150
151
		return $result;
152
	}
153
154
155
	/**
156
	 * Sends the notification e-mail for the given customer address and products
157
	 *
158
	 * @param \Aimeos\MShop\Customer\Item\Iface $item Customer item object
159
	 * @param array $products List of products a notification should be sent for
160
	 */
161
	protected function send( \Aimeos\MShop\Customer\Item\Iface $item, array $products )
162
	{
163
		$context = $this->context();
164
		$config = $context->config();
165
		$address = $item->getPaymentAddress();
166
167
		$view = $this->call( 'mailView', $address->getLanguageId() );
168
		$view->intro = $this->call( 'mailIntro', $address );
169
		$view->addressItem = $address;
170
		$view->products = $products;
171
		$view->urlparams = [
172
			'site' => $context->locale()->getSiteItem()->getCode(),
173
			'locale' => $address->getLanguageId(),
174
		];
175
176
		return $this->call( 'mailTo', $address )
177
			->subject( $context->translate( 'client', 'Your watched products' ) )
178
			->html( $view->render( $config->get( 'controller/jobs/customer/email/watch/template-html', 'customer/email/watch/html' ) ) )
179
			->text( $view->render( $config->get( 'controller/jobs/customer/email/watch/template-text', 'customer/email/watch/text' ) ) )
180
			->send();
181
	}
182
}
183