why use WeakReference for Handler still leak? - leakcanary

private static class MyHandler extends Handler {
private final WeakReference<ChannelPlayer> parentReference;
protected MyHandler(ChannelPlayer activity) {
parentReference = new WeakReference<>(activity);
}
#Override
public void handleMessage(Message msg) {
final ChannelPlayer parent = parentReference.get();
if (parent != null) {
runWithParent(parent, msg);
}
super.handleMessage(msg);
}
public void runWithParent(ChannelPlayer parent, Message msg){
switch (msg.what) {
case MEDIA_PLAYER_VIDEO_NETSPEED: {
parent.mMediaController.setDownloadRate(String.valueOf(msg.arg1) + "KB/s");
parent.mNetSpeed.setTextSize(30);
parent.mNetSpeed.setText(String.format(mNetSpeedText, String.valueOf(msg.arg1) + "KB/s"));
break;
}
case MEDIA_PLAYER_BUFFERING_UPDATE: {
break;
}
case MEDIA_PLAYER_COMPLETION: {
break;
}
case MEDIA_PLAYER_LONG_PREPERING: {
// 如果长时间没有完成prepering,也就是长时间没有加载进视频直接换台
// 播放错误了,自动换台
parent.sendChannelBroken();
parent.sendChannelSave(true);
parent.changeSource();
break;
}
case MEDIA_PLAYER_INFO: {
if (msg.arg1 == IMediaPlayer.MEDIA_INFO_NOT_SEEKABLE) {
parent.mCanSeek = false;
} else if (msg.arg1 == IMediaPlayer.MEDIA_INFO_BUFFERING_START) {
parent.mProgressBarPreparing.setVisibility(View.VISIBLE);
parent.mNetSpeed.setVisibility(View.VISIBLE);
/*
* if (parent.mMediaPlayer.isPlaying()) {
* parent.mMediaPlayer.pause(); }
*/
} else if (msg.arg1 == IMediaPlayer.MEDIA_INFO_BUFFERING_END) {
parent.mEventHandler.removeMessages(MEDIA_PLAYER_LONG_PREPERING);
parent.mProgressBarPreparing.setVisibility(View.GONE);
parent.mProgressBarPreparingText.setVisibility(View.GONE);
parent.mProgressBarPreparingEpgNextText.setVisibility(View.GONE);
parent.mProgressBarPreparingEpgCurrentText.setVisibility(View.GONE);
parent.mNetSpeed.setVisibility(View.GONE);
/*
* if (parent.mMediaPlayer.isPlaying()) {
* parent.mMediaPlayer.start(); }
*/
}
break;
}
case MEDIA_PLAYER_CHANGE_CHANNEL: {
parent.setProgressBarPreParingText();
parent.resetMediaPlayer();
break;
}
case MEDIA_PLAYER_SETED_DATASOURCE: {
parent.setDataSource(parent.mMediaPath);
parent.mChannelList.setSelection(parent.favListAdapter.getSelection());
break;
}
case MEDIA_PLAYER_NUM_UPDATE: {
// 更新数字建
int position = parent.favListAdapter.getPosition(parent.playerKeyNum);
if (position > -1) {
parent.changeChannel(parent.favListAdapter.getBean(position));
parent.setChannelListTitle();
} else {
parent.mPlayerKeyView.setText(R.string.player_worng_channel_number);
}
parent.playerKeyNum = -1;
parent.mEventHandler.sendEmptyMessageDelayed(MEDIA_PLAYER_NUMKEY_HIDDEN, 2000);
break;
}
case MEDIA_PLAYER_NUMKEY_HIDDEN: {
parent.hiddenPlayerKeyNum();
break;
}
case EPG_LIST_HIDDEN: {
parent.mChannelEpgList.setVisibility(View.GONE);
break;
}
case EPG_LIST_SHOWING: {
parent.mChannelEpgList.setVisibility(View.VISIBLE);
break;
}
default:
break;
}
}
}
In 'onCreate', I init the handler:
mEventHandler = new MyHandler(this);
and in onDestroy
mEventHandler.removeCallbacksAndMessages(null);
mEventHandler = null;
but it is still show leak!why?
03-18 20:49:40.135 14372-15987/tv.zvdio D/LeakCanary: In tv.zvdio:WTV-B-20160320:116.
03-18 20:49:40.135 14372-15987/tv.zvdio D/LeakCanary: * tv.zvdio.ui.player.ChannelPlayer has leaked:
03-18 20:49:40.135 14372-15987/tv.zvdio D/LeakCanary: * GC ROOT android.os.HandlerThread.<Java Local>
03-18 20:49:40.135 14372-15987/tv.zvdio D/LeakCanary: * leaks tv.zvdio.ui.player.ChannelPlayer instance
03-18 20:49:40.135 14372-15987/tv.zvdio D/LeakCanary: * Retaining: 5.8 MB.
03-18 20:49:40.135 14372-15987/tv.zvdio D/LeakCanary: * Reference Key: 4c2be65c-0924-44f2-ac68-333ff539507a
03-18 20:49:40.135 14372-15987/tv.zvdio D/LeakCanary: * Device: Xiaomi Xiaomi MI 3C cancro
03-18 20:49:40.135 14372-15987/tv.zvdio D/LeakCanary: * Android Version: 6.0.1 API: 23 LeakCanary: 1.4-beta1 02804f3
03-18 20:49:40.135 14372-15987/tv.zvdio D/LeakCanary: * Durations: watch=5020ms, gc=174ms, heap dump=6094ms, analysis=31821ms
03-18 20:49:40.135 14372-15987/tv.zvdio D/LeakCanary: * Details:
03-18 20:49:40.135 14372-15987/tv.zvdio D/LeakCanary: * Instance of android.os.HandlerThread
03-18 20:49:40.135 14372-15987/tv.zvdio D/LeakCanary: | mLooper = android.os.Looper#851452256 (0x32c02160)
03-18 20:49:40.135 14372-15987/tv.zvdio D/LeakCanary: | mPriority = 0
03-18 20:49:40.135 14372-15987/tv.zvdio D/LeakCanary: | mTid = 14895
03-18 20:49:40.135 14372-15987/tv.zvdio D/LeakCanary: | contextClassLoader = dalvik.system.PathClassLoader#851452736 (0x32c02340)
03-18 20:49:40.135 14372-15987/tv.zvdio D/LeakCanary: | daemon = false
03-18 20:49:40.135 14372-15987/tv.zvdio D/LeakCanary: | group = java.lang.ThreadGroup#1896861424 (0x710fcef0)
03-18 20:49:40.136 14372-15987/tv.zvdio D/LeakCanary: | hasBeenStarted = true
03-18 20:49:40.136 14372-15987/tv.zvdio D/LeakCanary: | id = 37566
03-18 20:49:40.136 14372-15987/tv.zvdio D/LeakCanary: | inheritableValues = null
03-18 20:49:40.136 14372-15987/tv.zvdio D/LeakCanary: | interruptActions = java.util.ArrayList#853002752 (0x32d7ca00)
03-18 20:49:40.136 14372-15987/tv.zvdio D/LeakCanary: | localValues = java.lang.ThreadLocal$Values#853002784 (0x32d7ca20)
03-18 20:49:40.136 14372-15987/tv.zvdio D/LeakCanary: | lock = java.lang.Object#851448048 (0x32c010f0)
03-18 20:49:40.136 14372-15987/tv.zvdio D/LeakCanary: | name = java.lang.String#851614976 (0x32c29d00)
03-18 20:49:40.136 14372-15987/tv.zvdio D/LeakCanary: | nativePeer = -1412130816
03-18 20:49:40.136 14372-15987/tv.zvdio D/LeakCanary: | parkBlocker = null
03-18 20:49:40.136 14372-15987/tv.zvdio D/LeakCanary: | parkState = 1
03-18 20:49:40.136 14372-15987/tv.zvdio D/LeakCanary: | priority = 5
03-18 20:49:40.136 14372-15987/tv.zvdio D/LeakCanary: | stackSize = 0
03-18 20:49:40.136 14372-15987/tv.zvdio D/LeakCanary: | target = null
03-18 20:49:40.136 14372-15987/tv.zvdio D/LeakCanary: | uncaughtHandler = null
03-18 20:49:40.136 14372-15987/tv.zvdio D/LeakCanary: | shadow$_klass_ = android.os.HandlerThread
03-18 20:49:40.136 14372-15987/tv.zvdio D/LeakCanary: | shadow$_monitor_ = 1252025007
03-18 20:49:40.136 14372-15987/tv.zvdio D/LeakCanary: * Instance of tv.zvdio.ui.player.ChannelPlayer
it is very sad.
btw, my app has two process, one is the main activity, another is used for media player, so when i finished the video activity, it is show leak.

Related

Laravel foreach not working into my product multiiple discount model?

I have build discount system based on product and user id, I have almost done everything i just got error in my laravel model bellow my code:
public static function discount($p_id)
{
$discount = Discount::where('user_id', Auth::user()->id )->first();
$p = Product::where('id', $p_id)->first();
$multidiscount = MultipleDiscount::where('user_id','like','%'.trim(Auth::user()->id).'%')->with('typeItems')->first();
$orderdetail = MultiDiscountType::where('multidiscount_id',$multidiscount->id)->pluck('value');
if( !is_null($multidiscount) || is_null($discount) ){
foreach ($multidiscount->typeItems as $key => $mdiscount) {
# code...
$discprice = explode(',', $orderdetail);
if( $discount->value <= $mdiscount->value ){
if( $mdiscount->type == 'percentage' ){
$p_val = $p->price / 100 * $mdiscount->value ;
$p_price = $p->price - $p_val;
}
}else{
if( $discount->type == 'percentage' ){
$p_val = $p->price / 100 * $discount->value;
$p_price = $p->price - $p_val;
}
else {
$p_val = $p->price - $discount->value;
$p_price = $p_val;
}
}
}
}
else {
$p_price = $p->price;
}
return $p_price;
}
I got nice result in my product blade view file but issue with in my multidiscount table have two rows but i get only last row value. Whats is the wrong i dont know bellow multiplediscount table structure:
Multi Discount Table:
|id| name |status |user_id|
|1 |Black Friday| active| 2, 3 |
I used repeater field for multiple discount based on product and user.
Multi Discount Table Item
|id| product it |value|discount_id|
|1 | 3 | 25 | 1 |
|2 | 2 | 20 | 1 |
Use get() instead of first() in your MultipleDiscount module to fetch all records:
$multidiscount = MultipleDiscount::where('user_id','like','%'.trim(Auth::user()->id).'%')->with('typeItems')->get();
Although I'm not sure why you are fetching the discounts for a specific user with the LIKE clause. For example, if you have a user with the ID of 10, this will return values for the users with the ID that somehow contains 10 like 1101, 1210212, ... and so on.
EDIT:
foreach ($multidiscount as $key => $mdiscount) {
# code...
$discprice = explode(',', $orderdetail);
if( $discount->value <= $mdiscount->typeItems->value ){
if( $mdiscount->typeItems->type == 'percentage' ){
$p_val = $p->price / 100 * $mdiscount->typeItems->value ;
$p_price = $p->price - $p_val;
}
}else{
if( $discount->type == 'percentage' ){
$p_val = $p->price / 100 * $discount->value;
$p_price = $p->price - $p_val;
}
else {
$p_val = $p->price - $discount->value;
$p_price = $p_val;
}
}
}

Laravel 9: AWS S3 retreiving a Video to Stream

After updating to Laravel 9.14 with PHP 8.1.4 then streaming has broke that was based on this answer https://stackoverflow.com/a/52598361/6825499.
I can see that it is because of a
Call to undefined method League\Flysystem\AwsS3V3\AwsS3V3Adapter::getClient()
So it seems to have been removed in the newest version from league/flysystem-aws-s3-v3 (3.0.13)
I did find a reference to this SO post which tries to explain there is a workaround now: Get S3Client from storage facade in Laravel 9
This is though too complex for me to understand.
Does anyone know what can be done?
You need to update the PHP version on your server to the latest one. It sounds like the server is still on the PHP 7.x version and that's the issue.
After researching quite a bit I realized that the issue came down to updates described in Laravel document page about upgrading.
I ended up altering the code a bit where I use environment variables to fill out what was before provieded by the adapter in the code.
In the latest version of the flysystem,there is no longer access to the client via the adapter. Due to mentioned reason, the service has been broken.
For a fully working class then you can use below code for laravel version 9
<?php
namespace App\Http;
use Exception;
use Illuminate\Filesystem\FilesystemAdapter;
use Illuminate\Http\Response;
use Illuminate\Support\Arr;
use Illuminate\Support\Str;
use League\Flysystem\Filesystem;
use Storage;
use Symfony\Component\HttpFoundation\StreamedResponse;
class S3FileStream
{
/**
* Name of adapter
*
* #var string
*/
private $adapterName;
/**
* Storage disk
*
* #var FilesystemAdapter
*/
private $disk;
/**
* #var int file end byte
*/
private $end;
/**
* #var string
*/
private $filePath;
/**
* Human-known filename
*
* #var string|null
*/
private $humanName;
/**
* #var bool storing if request is a range (or a full file)
*/
private $isRange = false;
/**
* #var int|null length of bytes requested
*/
private $length = null;
/**
* #var array
*/
private $returnHeaders = [];
/**
* #var int file size
*/
private $size;
/**
* #var string bucket name
*/
private $bucket;
/**
* #var int start byte
*/
private $start;
/**
* S3FileStream constructor.
* #param string $filePath
* #param string $adapter
* #param string $humanName
*/
public function __construct(string $filePath, string $adapter = 's3', ?string $humanName = null)
{
$options = [
'region' => env("AWS_DEFAULT_REGION"),
'version' => 'latest'
];
$this->filePath = $filePath;
$this->adapterName = $adapter;
$this->disk = Storage::disk($this->adapterName);
$this->client = new \Aws\S3\S3Client($options);
$this->humanName = $humanName;
$this->bucket = env("AWS_BUCKET");
//Set to zero until setHeadersAndStream is called
$this->start = 0;
$this->size = 0;
$this->end = 0;
}
/**
* Output file to client.
*/
public function output()
{
return $this->setHeadersAndStream();
}
/**
* Output headers to client.
* #return Response|StreamedResponse
*/
protected function setHeadersAndStream()
{
if (!$this->disk->exists($this->filePath)) {
report(new Exception('S3 File Not Found in S3FileStream - ' . $this->adapterName . ' - ' . $this->disk->path($this->filePath)));
return response('File Not Found', 404);
}
$this->start = 0;
$this->size = $this->disk->size($this->filePath);
$this->end = $this->size - 1;
$this->length = $this->size;
$this->isRange = false;
//Set headers
$this->returnHeaders = [
'Last-Modified' => $this->disk->lastModified($this->filePath),
'Accept-Ranges' => 'bytes',
'Content-Type' => $this->disk->mimeType($this->filePath),
'Content-Disposition' => 'inline; filename=' . ($this->humanName ?? basename($this->filePath) . '.' . Arr::last(explode('.', $this->filePath))),
'Content-Length' => $this->length,
];
//Handle ranges here
if (!is_null(request()->server('HTTP_RANGE'))) {
$cStart = $this->start;
$cEnd = $this->end;
$range = Str::after(request()->server('HTTP_RANGE'), '=');
if (strpos($range, ',') !== false) {
return response('416 Requested Range Not Satisfiable', 416, [
'Content-Range' => 'bytes */' . $this->size,
]);
}
if (substr($range, 0, 1) == '-') {
$cStart = $this->size - intval(substr($range, 1)) - 1;
} else {
$range = explode('-', $range);
$cStart = intval($range[0]);
$cEnd = (isset($range[1]) && is_numeric($range[1])) ? intval($range[1]) : $cEnd;
}
$cEnd = min($cEnd, $this->size - 1);
if ($cStart > $cEnd || $cStart > $this->size - 1) {
return response('416 Requested Range Not Satisfiable', 416, [
'Content-Range' => 'bytes */' . $this->size,
]);
}
$this->start = intval($cStart);
$this->end = intval($cEnd);
$this->length = min($this->end - $this->start + 1, $this->size);
$this->returnHeaders['Content-Length'] = $this->length;
$this->returnHeaders['Content-Range'] = 'bytes ' . $this->start . '-' . $this->end . '/' . $this->size;
$this->isRange = true;
}
return $this->stream();
}
/**
* Stream file to client.
* #throws Exception
* #return StreamedResponse
*/
protected function stream(): StreamedResponse
{
$this->client->registerStreamWrapper();
// Create a stream context to allow seeking
$context = stream_context_create([
's3' => [
'seekable' => true,
],
]);
// Open a stream in read-only mode
if (!($stream = fopen("s3://{$this->bucket}/{$this->filePath}", 'rb', false, $context))) {
throw new Exception('Could not open stream for reading export [' . $this->filePath . ']');
}
if (isset($this->start) && $this->start > 0) {
fseek($stream, $this->start, SEEK_SET);
}
$remainingBytes = $this->length ?? $this->size;
$chunkSize = 100;
$video = response()->stream(
function () use ($stream, $remainingBytes, $chunkSize) {
while (!feof($stream) && $remainingBytes > 0) {
$toGrab = min($chunkSize, $remainingBytes);
echo fread($stream, $toGrab);
$remainingBytes -= $toGrab;
flush();
}
fclose($stream);
},
($this->isRange ? 206 : 200),
$this->returnHeaders
);
return $video;
}
}

CodeIgniter --> Cookie paths cannot contain any of the following ',; \t\r\n\013\014' /xxxxx/system/libraries/Session/Session.php 170

I got following error
Cookie paths cannot contain any of the following ',; \t\r\n\013\014' /xxxxx/system/libraries/Session/Session.php 170
after setting
$config['cookie_path'] = '/; SameSite=Strict';
in config.php file. how to get rid of it?
You can solve your issue using this metod right here: https://github.com/bcit-ci/CodeIgniter/issues/5791#issuecomment-798956532
More exactly you need to set this in your application/config/config.php file:
$config['cookie_path'] = '/';
and replace the code from system/core/Input.php file from the line 289 to 352:
/**
* Set cookie
*
* Accepts an arbitrary number of parameters (up to 7) or an associative
* array in the first parameter containing all the values.
*
* #param string|mixed[] $name Cookie name or an array containing parameters
* #param string $value Cookie value
* #param int $expire Cookie expiration time in seconds
* #param string $domain Cookie domain (e.g.: '.yourdomain.com')
* #param string $path Cookie path (default: '/')
* #param string $prefix Cookie name prefix
* #param bool $secure Whether to only transfer cookies via SSL
* #param bool $httponly Whether to only makes the cookie accessible via HTTP (no javascript)
* #return void
*/
public function set_cookie($name, $value = '', $expire = 0, $domain = '', $path = '/', $prefix = '', $secure = NULL, $httponly = NULL)
{
if (is_array($name))
{
// always leave 'name' in last place, as the loop will break otherwise, due to $$item
foreach (array('value', 'expire', 'domain', 'path', 'prefix', 'secure', 'httponly', 'name') as $item)
{
if (isset($name[$item]))
{
$$item = $name[$item];
}
}
}
if ($prefix === '' && config_item('cookie_prefix') !== '')
{
$prefix = config_item('cookie_prefix');
}
if ($domain == '' && config_item('cookie_domain') != '')
{
$domain = config_item('cookie_domain');
}
if ($path === '/' && config_item('cookie_path') !== '/')
{
$path = config_item('cookie_path');
}
$secure = ($secure === NULL && config_item('cookie_secure') !== NULL)
? (bool) config_item('cookie_secure')
: (bool) $secure;
$httponly = ($httponly === NULL && config_item('cookie_httponly') !== NULL)
? (bool) config_item('cookie_httponly')
: (bool) $httponly;
if ( ! is_numeric($expire) OR $expire < 0)
{
$expire = 1;
}
else
{
$expire = ($expire > 0) ? time() + $expire : 0;
}
setcookie($prefix.$name, $value, $expire, $path, $domain, $secure, $httponly);
}

No such entity with customerId = 1

I have a magento 2.3.2 and tried to do the order.After completing the order,success page is not redirected.But the order has created. Can anyone tell what will be issue. Below I'm getting in error log
main.CRITICAL: No such entity with customerId = 1 {"exception":"[object]
(Magento\\Framework\\Exception\\NoSuchEntityException(code: 0): No such entity
with customerId = 1 at /opt/magento/public_html/vendor/magento/framework/Exception/NoSuchEntityException.php:50)"} []main.CRITICAL: No such entity with customerId = 1 {"exception":"[object] (Magento\\Framework\\Exception\\NoSuchEntityException(code: 0): No such entity with customerId = 1 at /opt/magento/public_html/vendor/magento/framework/Exception/NoSuchEntityException.php:50)"} []main.CRITICAL: No such entity with customerId = 1 {"exception":"[object] (Magento\\Framework\\Exception\\NoSuchEntityException(code: 0): No such entity with customerId = 1 at /opt/magento/public_html/vendor/magento/framework/Exception/NoSuchEntityException.php:50)"} [](END)
Please apply this patch in 2.3.2 https://patch-diff.githubusercontent.com/raw/magento/magento2/pull/25307.diff
Or upgrade to 2.3.4
Source: https://github.com/magento/magento2/pull/25307
Apply this patch:
diff --git a/app/code/Magento/Checkout/Model/Session.php b/app/code/Magento/Checkout/Model/Session.php
index a654c78853d7..4a4861fa9ccd 100644
--- a/app/code/Magento/Checkout/Model/Session.php
+++ b/app/code/Magento/Checkout/Model/Session.php
## -7,6 +7,8 ##
use Magento\Customer\Api\Data\CustomerInterface;
use Magento\Framework\App\ObjectManager;
+use Magento\Framework\Exception\NoSuchEntityException;
+use Magento\Quote\Api\Data\CartInterface;
use Magento\Quote\Model\Quote;
use Magento\Quote\Model\QuoteIdMaskFactory;
use Psr\Log\LoggerInterface;
## -21,9 +23,6 ##
*/
class Session extends \Magento\Framework\Session\SessionManager
{
- /**
- * Checkout state begin
- */
const CHECKOUT_STATE_BEGIN = 'begin';
/**
## -228,7 +227,7 ## public function setLoadInactive($load = true)
*
* #return Quote
* #throws \Magento\Framework\Exception\LocalizedException
- * #throws \Magento\Framework\Exception\NoSuchEntityException
+ * #throws NoSuchEntityException
* #SuppressWarnings(PHPMD.CyclomaticComplexity)
* #SuppressWarnings(PHPMD.NPathComplexity)
*/
## -273,21 +272,17 ## public function getQuote()
*/
$quote = $this->quoteRepository->get($this->getQuoteId());
}
- } catch (\Magento\Framework\Exception\NoSuchEntityException $e) {
+ } catch (NoSuchEntityException $e) {
$this->setQuoteId(null);
}
}
if (!$this->getQuoteId()) {
if ($this->_customerSession->isLoggedIn() || $this->_customer) {
- $customerId = $this->_customer
- ? $this->_customer->getId()
- : $this->_customerSession->getCustomerId();
- try {
- $quote = $this->quoteRepository->getActiveForCustomer($customerId);
- $this->setQuoteId($quote->getId());
- } catch (\Magento\Framework\Exception\NoSuchEntityException $e) {
- $this->logger->critical($e);
+ $quoteByCustomer = $this->getQuoteByCustomer();
+ if ($quoteByCustomer !== null) {
+ $this->setQuoteId($quoteByCustomer->getId());
+ $quote = $quoteByCustomer;
}
} else {
$quote->setIsCheckoutCart(true);
## -375,7 +370,7 ## public function loadCustomerQuote()
try {
$customerQuote = $this->quoteRepository->getForCustomer($this->_customerSession->getCustomerId());
- } catch (\Magento\Framework\Exception\NoSuchEntityException $e) {
+ } catch (NoSuchEntityException $e) {
$customerQuote = $this->quoteFactory->create();
}
$customerQuote->setStoreId($this->_storeManager->getStore()->getId());
## -558,7 +553,7 ## public function restoreQuote()
$this->replaceQuote($quote)->unsLastRealOrderId();
$this->_eventManager->dispatch('restore_quote', ['order' => $order, 'quote' => $quote]);
return true;
- } catch (\Magento\Framework\Exception\NoSuchEntityException $e) {
+ } catch (NoSuchEntityException $e) {
$this->logger->critical($e);
}
}
## -588,4 +583,22 ## protected function isQuoteMasked()
{
return $this->isQuoteMasked;
}
+
+ /**
+ * Returns quote for customer if there is any
+ */
+ private function getQuoteByCustomer(): ?CartInterface
+ {
+ $customerId = $this->_customer
+ ? $this->_customer->getId()
+ : $this->_customerSession->getCustomerId();
+
+ try {
+ $quote = $this->quoteRepository->getActiveForCustomer($customerId);
+ } catch (NoSuchEntityException $e) {
+ $quote = null;
+ }
+
+ return $quote;
+ }
}
diff --git a/app/code/Magento/Checkout/Test/Unit/Model/SessionTest.php b/app/code/Magento/Checkout/Test/Unit/Model/SessionTest.php
index 26234992e613..969631901adf 100644
--- a/app/code/Magento/Checkout/Test/Unit/Model/SessionTest.php
+++ b/app/code/Magento/Checkout/Test/Unit/Model/SessionTest.php
## -9,7 +9,8 ##
*/
namespace Magento\Checkout\Test\Unit\Model;
-use \Magento\Checkout\Model\Session;
+use Magento\Checkout\Model\Session;
+use Magento\Framework\Exception\NoSuchEntityException;
/**
* #SuppressWarnings(PHPMD.CouplingBetweenObjects)
## -374,6 +375,68 ## public function testGetStepData()
$this->assertEquals($stepData['complex']['key'], $session->getStepData('complex', 'key'));
}
+ /**
+ * Ensure that if quote not exist for customer quote will be null
+ *
+ * #return void
+ */
+ public function testGetQuote(): void
+ {
+ $storeManager = $this->getMockForAbstractClass(\Magento\Store\Model\StoreManagerInterface::class);
+ $customerSession = $this->createMock(\Magento\Customer\Model\Session::class);
+ $quoteRepository = $this->createMock(\Magento\Quote\Api\CartRepositoryInterface::class);
+ $quoteFactory = $this->createMock(\Magento\Quote\Model\QuoteFactory::class);
+ $quote = $this->createMock(\Magento\Quote\Model\Quote::class);
+ $logger = $this->createMock(\Psr\Log\LoggerInterface::class);
+ $loggerMethods = get_class_methods(\Psr\Log\LoggerInterface::class);
+
+ $quoteFactory->expects($this->once())
+ ->method('create')
+ ->willReturn($quote);
+ $customerSession->expects($this->exactly(3))
+ ->method('isLoggedIn')
+ ->willReturn(true);
+ $store = $this->getMockBuilder(\Magento\Store\Model\Store::class)
+ ->disableOriginalConstructor()
+ ->setMethods(['getWebsiteId', '__wakeup'])
+ ->getMock();
+ $storeManager->expects($this->any())
+ ->method('getStore')
+ ->will($this->returnValue($store));
+ $storage = $this->getMockBuilder(\Magento\Framework\Session\Storage::class)
+ ->disableOriginalConstructor()
+ ->setMethods(['setData', 'getData'])
+ ->getMock();
+ $storage->expects($this->at(0))
+ ->method('getData')
+ ->willReturn(1);
+ $quoteRepository->expects($this->once())
+ ->method('getActiveForCustomer')
+ ->willThrowException(new NoSuchEntityException());
+
+ foreach ($loggerMethods as $method) {
+ $logger->expects($this->never())->method($method);
+ }
+
+ $quote->expects($this->once())
+ ->method('setCustomer')
+ ->with(null);
+
+ $constructArguments = $this->_helper->getConstructArguments(
+ \Magento\Checkout\Model\Session::class,
+ [
+ 'storeManager' => $storeManager,
+ 'quoteRepository' => $quoteRepository,
+ 'customerSession' => $customerSession,
+ 'storage' => $storage,
+ 'quoteFactory' => $quoteFactory,
+ 'logger' => $logger
+ ]
+ );
+ $this->_session = $this->_helper->getObject(\Magento\Checkout\Model\Session::class, $constructArguments);
+ $this->_session->getQuote();
+ }
+
public function testSetStepData()
{
$stepData = [

Yootheme Zoo Image Watermark

I have use the yootheme zoo applications. I need to add watermark to zoo images.
This is zoo image progress file:
<?php
/**
* #package com_zoo
* #author YOOtheme http://www.yootheme.com
* #copyright Copyright (C) YOOtheme GmbH
* #license http://www.gnu.org/licenses/gpl.html GNU/GPL
*/
/**
* Image thumbnail helper class.
*
* #package Component.Helpers
* #since 2.0
*/
class ImageThumbnailHelper extends AppHelper {
/**
* Creates an AppImageThumbnail instance
*
* #param string $file The filepath
*
* #return AppImageThumbnail
*
* #since 2.0
*/
public function create($file) {
return $this->app->object->create('AppImageThumbnail', array($file));
}
/**
* Checks for the required php functions
*
* #return boolean
*
* #since 2.0
*/
public function check() {
$gd_functions = array(
'getimagesize',
'imagecreatefromgif',
'imagecreatefromjpeg',
'imagecreatefrompng',
'imagecreatetruecolor',
'imagecopyresized',
'imagecopy',
'imagegif',
'imagejpeg',
'imagepng'
);
foreach ($gd_functions as $name) {
if (!function_exists($name)) return false;
}
return true;
}
}
/**
* Image thumbnail class.
*
* #package Component.Helpers
* #since 2.0
*/
class AppImageThumbnail {
/**
* App instance
*
* #var App
* #since 2.0
*/
public $app;
/**
* The image file path
* #var string
*/
public $img_file;
/**
* The image format
* #var string
*/
public $img_format;
/**
* The image source
* #var resource
*/
public $img_source;
/**
* The image width
* #var string
*/
public $img_width;
/**
* The image height
* #var string
*/
public $img_height;
/**
* The thumb width
* #var string
*/
public $thumb_width;
/**
* The thumb height
* #var string
*/
public $thumb_height;
/**
* The thumb resize
* #var boolean
*/
public $thumb_resize;
/**
* The thumb quality
* #var int
*/
public $thumb_quality;
/**
* Class constructor
*
* #param string $file The file path.
* #since 2.0
*/
public function __construct($file) {
$this->img_file = $file;
$this->thumb_resize = true;
$this->thumb_quality = 90;
// get image info
list($width, $height, $type, $attr) = #getimagesize($this->img_file, $info);
// set image dimensions and type
if (is_array($info)) {
$this->img_width = $width;
$this->img_height = $height;
$this->thumb_width = $width;
$this->thumb_height = $height;
switch ($type) {
case 1:
$this->img_format = 'gif';
$this->img_source = imagecreatefromgif($this->img_file);
break;
case 2:
$this->img_format = 'jpeg';
$this->img_source = imagecreatefromjpeg($this->img_file);
break;
case 3:
$this->img_format = 'png';
$this->img_source = imagecreatefrompng($this->img_file);
break;
default:
$this->img_format = null;
$this->img_source = null;
break;
}
}
}
/**
* Set resize
*
* #param boolean $resize Resize value
*
* #return void
* #since 2.0
*/
public function setResize($resize) {
$this->thumb_resize = $resize;
}
/**
* Set thumb dimensions
*
* #param int $width
* #param int $height
*
* #return void
* #since 2.0
*/
public function setSize($width, $height) {
$this->thumb_width = $width;
$this->thumb_height = $height;
}
/**
* Size thumb width
*
* #param int $width
*
* #return void
* #since 2.0
*/
public function sizeWidth($width) {
$this->thumb_width = $width;
$this->thumb_height = #($width / $this->img_width) * $this->img_height;
}
/**
* Size thumb height
*
* #param int $height
*
* #return void
* #since 2.0
*/
public function sizeHeight($height) {
$this->thumb_width = #($height / $this->img_height) * $this->img_width;
$this->thumb_height = $height;
}
/**
* Save file
*
* #param string $file the file to save
*
* #return boolean true on success
* #since 2.0
*/
public function save($file) {
$return = false;
if ($this->img_format) {
$src = $this->img_source;
$src_x = 0;
$src_y = 0;
// smart resize thumbnail image
if ($this->thumb_resize) {
$resized_width = #($this->thumb_height / $this->img_height) * $this->img_width;
$resized_height = #($this->thumb_width / $this->img_width) * $this->img_height;
if ($this->thumb_width <= $resized_width) {
$width = $resized_width;
$height = $this->thumb_height;
$src_x = intval(($resized_width - $this->thumb_width) / 2);
} else {
$width = $this->thumb_width;
$height = $resized_height;
$src_y = intval(($resized_height - $this->thumb_height) / 2);
}
$src = imagecreatetruecolor($width, $height);
// save transparent colors
if ($this->img_format == 'png') {
imagecolortransparent($src, imagecolorallocate($src, 0, 0, 0));
imagealphablending($src, false);
imagesavealpha($src, true);
}
// get and reallocate transparency-color for gif
if ($this->img_format == 'gif') {
imagealphablending($src, false);
$transindex = imagecolortransparent($this->img_source) <= imagecolorstotal($src) ? imagecolortransparent($this->img_source) : imagecolorstotal($src);
if ($transindex >= 0) {
$transcol = imagecolorsforindex($this->img_source, $transindex);
$transindex = imagecolorallocatealpha($src, $transcol['red'], $transcol['green'], $transcol['blue'], 127);
imagefill($src, 0, 0, $transindex);
}
}
if (function_exists('imagecopyresampled')) {
#imagecopyresampled($src, $this->img_source, 0, 0, 0, 0, $width, $height, $this->img_width, $this->img_height);
} else {
#imagecopyresized($src, $this->img_source, 0, 0, 0, 0, $width, $height, $this->img_width, $this->img_height);
}
// restore transparency for gif
if ($this->img_format == 'gif') {
if ($transindex >= 0) {
imagecolortransparent($src, $transindex);
for ($y=0; $y < imagesy($src); ++$y) {
for ($x=0; $x < imagesx($src); ++$x) {
if (((imagecolorat($src, $x, $y)>>24) & 0x7F) >= 100) {
imagesetpixel($src, $x, $y, $transindex);
}
}
}
}
}
}
// create thumbnail image
$thumbnail = imagecreatetruecolor($this->thumb_width, $this->thumb_height);
// save transparent colors for png
if ($this->img_format == 'png') {
imagecolortransparent($thumbnail, imagecolorallocate($src, 0, 0, 0));
imagealphablending($thumbnail, false);
imagesavealpha($thumbnail, true);
}
// get and reallocate transparency-color for gif
if ($this->img_format == 'gif') {
imagealphablending($thumbnail, false);
$transindex = imagecolortransparent($src);
if ($transindex >= 0) {
$transcol = imagecolorsforindex($src, $transindex);
$transindex = imagecolorallocatealpha($thumbnail, $transcol['red'], $transcol['green'], $transcol['blue'], 127);
imagefill($thumbnail, 0, 0, $transindex);
}
}
#imagecopy($thumbnail, $src, 0, 0, $src_x, $src_y, $this->thumb_width, $this->thumb_height);
// restore transparency for gif
if ($this->img_format == 'gif') {
if ($transindex >= 0) {
imagecolortransparent($thumbnail, $transindex);
for ($y=0; $y < imagesy($thumbnail); ++$y) {
for ($x=0; $x < imagesx($thumbnail); ++$x) {
if (((imagecolorat($thumbnail, $x, $y)>>24) & 0x7F) >= 100) {
imagesetpixel($thumbnail, $x, $y, $transindex);
}
}
}
}
}
// save thumbnail to file
ob_start();
switch ($this->img_format) {
case 'gif':
$return = imagegif($thumbnail);
break;
case 'jpeg':
$return = imagejpeg($thumbnail, null, $this->thumb_quality);
break;
case 'png':
$return = imagepng($thumbnail);
break;
}
$output = ob_get_contents();
ob_end_clean();
JFile::write($file, $output);
// free memory resources
imagedestroy($thumbnail);
imagedestroy($src);
}
return $return;
}
}
And I find this code:
#imagecopy($thumbnail, $src, 0, 0, $src_x, $src_y, $this->thumb_width, $this->thumb_height);
Now how can I add watermark to this file?
You can use a 3rd Party Joomla plugin like Supermarks Pro. Works on all images except those fired inside lightboxes.

Resources