Magento 2 - Newsletter subscription issue - magento2

I use Martfury theme. When I subscribe to newsletter, it redirects me to /newsletter/subscriber/new/ and there is this message (JSON): {"success":true,"message":"Thank you for your subscription.","redirect":false}
Image:
It should show only notification and not redirect to that URL. In Martfury theme demo it works well.
Code:

In your theme, please check the newsletter controller return. Debug execute function line by line.
controller path: module-newsletter/Controller/Subscriber/NewAction
Then you can check the below function:
/**
* New subscription action
*
* #return Redirect
*/
public function execute()
{
if ($this->getRequest()->isPost() && $this->getRequest()->getPost('email')) {
$email = (string)$this->getRequest()->getPost('email');
try {
$this->validateEmailFormat($email);
$this->validateGuestSubscription();
$this->validateEmailAvailable($email);
$websiteId = (int)$this->_storeManager->getStore()->getWebsiteId();
/** #var Subscriber $subscriber */
$subscriber = $this->_subscriberFactory->create()->loadBySubscriberEmail($email, $websiteId);
if ($subscriber->getId()
&& (int)$subscriber->getSubscriberStatus() === Subscriber::STATUS_SUBSCRIBED) {
throw new LocalizedException(
__('This email address is already subscribed.')
);
}
$storeId = (int)$this->_storeManager->getStore()->getId();
$currentCustomerId = $this->getCustomerId($email, $websiteId);
$subscriber = $currentCustomerId
? $this->subscriptionManager->subscribeCustomer($currentCustomerId, $storeId)
: $this->subscriptionManager->subscribe($email, $storeId);
$message = $this->getSuccessMessage((int)$subscriber->getSubscriberStatus());
$this->messageManager->addSuccessMessage($message);
} catch (LocalizedException $e) {
$this->messageManager->addComplexErrorMessage(
'localizedSubscriptionErrorMessage',
['message' => $e->getMessage()]
);
} catch (\Exception $e) {
$this->messageManager->addExceptionMessage($e, __('Something went wrong with the subscription.'));
}
}
/** #var Redirect $redirect */
$redirect = $this->resultFactory->create(ResultFactory::TYPE_REDIRECT);
// phpcs:ignore Magento2.Legacy.ObsoleteResponse
$redirectUrl = $this->_redirect->getRedirectUrl();
return $redirect->setUrl($redirectUrl);
}

Related

The controller must return a response (Object(AppBundle\\Entity\\User) given)

I got this message "The controller must return a response (Object(App Bundle\Entity\User) given)." when i try to PATCH with postman a user password or username ... please help
BUT the username or password change ... ! i don't know why but that's working just the message is not good ...
My Userscontroller :
use AppBundle\Entity\EntityMerger;
use AppBundle\Entity\User;
use AppBundle\Exception\ResourceValidationException;
use Lexik\Bundle\JWTAuthenticationBundle\Encoder\JWTEncoderInterface;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;
use Symfony\Component\Validator\ConstraintViolationListInterface;
use FOS\RestBundle\Controller\Annotations as Rest;
/**
* #Security("is_anonymous() or is_authenticated()")
*/
class UsersController extends AbstractController
{
/**
* #var UserPasswordEncoderInterface
*/
private $passwordEncoder;
/**
* #var JWTEncoderInterface
*/
private $jwtEncoder;
/**
* #var EntityMerger
*/
private $entityMerger;
/**
* UsersController constructor.
* #param UserPasswordEncoderInterface $passwordEncoder
* #param JWTEncoderInterface $jwtEncoder
* #param EntityMerger $entityMerger
*/
public function __construct(UserPasswordEncoderInterface $passwordEncoder, JWTEncoderInterface $jwtEncoder, EntityMerger $entityMerger)
{
$this->passwordEncoder = $passwordEncoder;
$this->jwtEncoder = $jwtEncoder;
$this->entityMerger = $entityMerger;
}
/**
* #Rest\View()
* #Security("is_granted('show', theUser)", message="Access denied")
*/
public function getUserAction(?User $theUser)
{
if (null === $theUser) {
throw new NotFoundHttpException();
}
return $theUser;
}
/**
*
* #Rest\Post(
* path = "/users",
* name = "users_add"
* )
* #Rest\View(StatusCode=201)
* #ParamConverter(
* "user",
* converter="fos_rest.request_body",
* options={"deserializationContent"={"groups"={"Deserialize"}}}
* )
*/
public function postUserAction(User $user,
ConstraintViolationListInterface $violations)
{
if (count($violations) > 0) {
$message = 'The user is not valid: ';
foreach ($violations as $violation) {
$message .= sprintf(
"Field %s: %s ",
$violation->getPropertyPath(),
$violation->getMessage()
);
}
throw new ResourceValidationException($message);
}
$this->encodePassword($user);
$user->setRoles([User::ROLE_USER]);
$this->persistUser($user);
return $user;
}
/**
* #Rest\Patch(
* path = "/users/{theUser}",
* name= "patch_user"
* )
* #ParamConverter(
* "modifiedUser",
* converter="fos_rest.request_body",
* options={
* "validator"={"groups"={"Patch"}},
* "deserializationContext"={"groups"={"Deserialize"}}
* }
* )
* #Security("is_granted('edit', theUser)", message="Access Denied")
*/
public function patchUserAction(?User $theUser, User $modifiedUser,
ConstraintViolationListInterface $violations)
{
if (null === $theUser) {
throw new NotFoundHttpException();
}
if (empty($modifiedUser->getPassword())) {
$modifiedUser->setPassword(null);
}
if (count($violations) > 0) {
$message = 'The user is not valid: ';
foreach ($violations as $violation) {
$message .= sprintf(
"Field %s: %s",
$violation->getPropertyPath(),
$violation->getMessage()
);
}
throw new ResourceValidationException($message);
}
$this->entityMerger->merge($theUser, $modifiedUser);
$this->encodePassword($theUser);
$this->persistUser($theUser);
return $theUser;
}
/**
* #param User $user
*/
protected function encodePassword(User $user): void
{
$user->setPassword(
$this->passwordEncoder->encodePassword(
$user,
$user->getPassword()
)
);
}
/**
* #param User $user
*/
protected function persistUser(User $user): void
{
$em = $this->getDoctrine()->getManager();
$em->persist($user);
$em->flush();
}
}
My EntityMerger:
namespace AppBundle\Entity;
use Doctrine\Common\Annotations\Reader as AnnotationReader;
use Doctrine\ORM\Mapping\Id;
class EntityMerger
{
/**
* #var AnnotationReader
*/
private $annotationReader;
public function __construct(AnnotationReader $annotationReader)
{
$this->annotationReader = $annotationReader;
}
/**
* #param $entity
* #param $changes
*/
public function merge($entity, $changes)
{
$entityClassName = get_class($entity);
if (false === $entityClassName) {
throw new \InvalidArgumentException('$entity is not a class');
}
$changesClassName = get_class($changes);
if (false == $changesClassName) {
throw new \InvalidArgumentException('$entity is not a class');
}
if (!is_a($changes, $entityClassName)) {
throw new \InvalidArgumentException("Cannot merge object of class $changesClassName with object of class $entityClassName");
}
$entityReflection = new \ReflectionObject($entity);
$changesReflection = new \ReflectionObject($changes);
foreach ($changesReflection->getProperties() as $changedProperty) {
$changedProperty->setAccessible(true);
$changedPropertyValue = $changedProperty->getValue($changes);
if(null === $changedPropertyValue) {
continue;
}
if (!$entityReflection->hasProperty($changedProperty->getName())) {
continue;
}
$entityProperty = $entityReflection->getProperty($changedProperty->getName());
$annotation = $this->annotationReader->getPropertyAnnotation($entityProperty, Id::class);
if (null !== $annotation) {
continue;
}
$entityProperty->setAccessible(true);
$entityProperty->setValue($entity, $changedPropertyValue);
}
}
}
The message correctly states that you are not returning a response object.
From the manual, The only requirement for a controller is to return a Response object
If you want to return an object you could return JSON:
return $this->json(['user' => $theUser]);
This is just a guess from your code, because your question does not state what you want to return.

Too many Redirects with Controller

When I try to define my routes with an ImagesController, I get a "site redirected you too many times" error when going to what should be the index. I'm stumped. Am I over-tired and not seeing something obvious?
web.php
Route::prefix('images')->group(function(){
Route::post('add-tag', 'ImagesController#addTag');
Route::get('test', 'ImagesController#index');
});
When I access /images/test, the controller responds correctly. When I have it defined as '' or / it redirects too much. I'm not setting them simultaneously.
Route::prefix('images')->group(function(){
Route::post('add-tag', 'ImagesController#addTag');
// like this:
Route::get('', 'ImagesController#index');
// or like the following:
Route::get('/', 'ImagesController#index');
});
I've even tried to define /images before the prefix group to no avail. images/test is fine in this case.
Route::get('images', 'ImagesController#index');
Route::prefix('images')->group(function(){
Route::post('add-tag', 'ImagesController#addTag');
Route::get('test', 'ImagesController#index');
});
ImagesController.php
namespace App\Http\Controllers;
use \Auth;
use App\Helpers;
use App\Image;
use App\Tag;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
use Symfony\Component\Console\Helper\Helper;
class ImagesController extends Controller
{
private $sortBy = [
'created_at',
'updated_at',
'orig_name',
'orig_size'
];
private $defaultSortBy = 'created_at';
private $defaultOrder = 'desc';
/**
* #param Request $request
* #return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
*/
public function index(Request $request)
{
$sort = $request->get('sort', $this->defaultSortBy);
$sort = in_array($sort, $this->sortBy) ? $sort : 'created_at';
$order = $request->get('order', $this->defaultOrder);
$order = $order == 'desc' ? 'desc' : 'asc';
$images = Image::orderBy($sort, $order)
->whereQuestionable(0)
->wherePrivate(0)
->paginate(config('image.images_per_page'));
if ($images !== null && $sort !== $this->defaultSortBy) {
$images->appends(['sort' => $sort]);
}
if ($images !== null && $order !== $this->defaultOrder) {
$images->appends(['order' => $order]);
}
return view(
'images.index',
[
'images' => $images,
'sort' => $sort,
'order' => $order
]
);
}
/**
* Show the form for creating a new resource.
*
* #return \Illuminate\Http\Response
*/
public function create()
{
//
}
/**
* Store a newly created resource in storage.
*
* #param \Illuminate\Http\Request $request
* #return \Illuminate\Http\Response
*/
public function store(Request $request)
{
//
}
/**
* Display the specified resource.
*
* #param int $id
* #return \Illuminate\Http\Response
*/
public function show($id)
{
//
}
/**
* Show the form for editing the specified resource.
*
* #param int $id
* #return \Illuminate\Http\Response
*/
public function edit($id)
{
//
}
/**
* Update the specified resource in storage.
*
* #param \Illuminate\Http\Request $request
* #param int $id
* #return \Illuminate\Http\Response
*/
public function update(Request $request, $id)
{
//
}
/**
* Remove the specified resource from storage.
*
* #param int $id
* #return \Illuminate\Http\Response
*/
public function destroy($id)
{
//
}
//this function works correctly, but I suppose it may be interfering?
public function addTag(Request $request)
{
Log::debug(print_r($request->all(), true));
$error = '';
$uid = trim($request->input('uid', ''));
$newTag = Helpers::prepTag($request->input('tag', ''));
if (!Auth::check()){
$error .= 'You can only add tags to images if you are logged in.';
} else if ($uid === '' || $newTag === '') {
$error .= 'UID and tag cannot be empty';
} else {
$image = Image::whereUid($uid)->unQuestionable()->first();
$currentTags = [];
if (count($image->tags)){
foreach ($image->tags as $currentTag) {
$currentTags[$currentTag->id] = $currentTag->tag;
}
}
if ($image === null) {
$error .= "Image $uid was not found.";
} else {
$tag = Tag::firstOrNew(['tag'=>$newTag]);
if ($tag->ip == '') {
$tag->ip = $request->getClientIp();
$tag->user_id = Auth::check() ? Auth::user()->id : 5;
$tag->save();
}
//\Log::info(print_r($currentTags, true));
//\Log::info(print_r($tag, true));
$addTag = !(bool)isset($currentTags[$tag->id]);
$image->tags()->sync([$tag->id], false);
}
}
if ($request->ajax()) {
if ($error !== '') {
return response()->json(['message' => $error],400);
}
return response()->json(['tagId' => $tag->id, 'imageUid' => $image->uid, 'tag' => $tag->tag, 'isAdmin' => true, 'addTag' => $addTag]);
} else {
if ($error !== '') {
Helpers::alert(3, $error, 'Tag Not Added');
}
return redirect('/');
}
}
}
As I have a model named Images implicit binding was interfering with my defined routes for a controller with the name ImagesController, and applying the prefix /images. After changing the name in the routing to image this issue went away.

How to get all order payment method information in magento2

I try to get order related information like order status, total amount, payment method etc.
I got order status using
$_order->getStatusLabel();
But how I get payment method-related information in Magento 2.
In Block file
/** #var \Magento\Sales\Model\ResourceModel\Order\Payment\Collection */
protected $_paymentCollectionFactory;
/** #var \Magento\Sales\Model\ResourceModel\Order\CollectionFactory */
protected $_orderCollectionFactory;
/** #var \Magento\Sales\Model\ResourceModel\Order\Collection */
protected $orders;
public function __construct(
\Magento\Framework\View\Element\Template\Context $context,\Magento\Sales\Model\ResourceModel\Order\CollectionFactory $orderCollectionFactory, \Magento\Sales\Model\ResourceModel\Order\Payment\CollectionFactory $paymentCollectionFactory, array $data = []
) {
$this->_orderCollectionFactory = $orderCollectionFactory;
$this->_paymentCollectionFactory = $paymentCollectionFactory;
parent::__construct($context, $data);
}
public function getPaymentsCollection() {
$collection = $this->_paymentCollectionFactory->create()->addFieldToSelect('*');
return $collection;
}
public function getOrders($storeId) {
if (!$this->orders) {
$this->orders = $this->_orderCollectionFactory->create()->addFieldToSelect('*');
}
return $this->orders;
}
In phtml file
$_orders = $block->getOrders();
if ($_orders && count($_orders)) {
$payments = $block->getPaymentsCollection();
$chekmo = $cod = $free = $bank = $paypalgrp = 0;
foreach ($payments as $_payment) {
$method = $_payment->getMethod();
switch ($method) {
case 'checkmo' : $chekmo++;
break;
case 'cashondelivery' : $cod++;
break;
case 'free' : $free++;
break;
case 'banktransfer' : $bank++;
break;
case 'paypal_group_all_in_one' : $paypalgrp++;
break;
}
}
echo "Payment Methods<br>";
echo "Check / Money Order Methods " . $ckeckmo;
echo "Cash on Delivery Methods " . $cod;
echo "Free Methods " . $free;
echo "Bank Transfer Methods " . $bank;
echo "Paypal group all in one Methods " . $paypalgrp;
}
else{
echo "You have no Orders";
}
Following code will be helpful
$orderId = 1001;
$order = $this->order->load($orderId);
$method=$order->getPayment()->getMethod();
$expmonth=$order->getPayment()->getCcExpMonth();
$expyear=$order->getPayment()->getCcExpYear();
$cclast4=$order->getPayment()->getCcLast4();
$ipaddress=$order->getRemoteIp();
$billingaddress=$order->getBillingAddress();
$billingcity=$billingaddress->getCity();
$billingstreet=$billingaddress->getStreet();
$billingpostcode=$billingaddress->getPostcode();
$billingtelephone=$billingaddress->getTelephone();
$billingstate_code=$billingaddress->getRegionCode();
$shippingaddress=$order->getShippingAddress();
$shippingcity=$shippingaddress->getCity();
$shippingstreet=$shippingaddress->getStreet();
$shippingpostcode=$shippingaddress->getPostcode();
$shippingtelephone=$shippingaddress->getTelephone();
$shippingstate_code=$shippingaddress->getRegionCode();
$tax_amount=$order->getTaxAmount();
$total=$order->getGrandTotal();
It's work like a charm

Symfony2, Keep form data across redirect

How to use session for retrieving data during redirect? I am getting the error message: "exception 'Symfony\Component\Form\Exception\AlreadySubmittedException' with message 'You cannot change the data of a submitted form."
C:\Bitnami\wampstack-5.5.30-0\sym_prog\proj3_27\src\MeetingBundle\Controller\UserController.php
/**
* Creates a new User entity.
*
* #Route("/new", name="user_new")
* #Method({"GET", "POST"})
*/
public function newAction(Request $request)
{
$user = new User();
$form = $this->createForm(new UserType(), $user);
$form->handleRequest($request);
$session = $this->getRequest()->getSession();
$form->setData(unserialize($session->get('userFilter')));
if ( $form->isSubmitted() && $form->isValid() ) {
$session->set( 'userFilter', serialize($form->getData()) );
$em = $this->getDoctrine()->getManager();
$em->persist($user);
$em->flush();
return $this->redirectToRoute('user_edit', array('id' => $user->getId()));
}
return $this->render('MeetingBundle::user/new.html.twig', array(
'user' => $user,
'form' => $form->createView(),
));
} // public function newAction(Request $request)
C:\Bitnami\wampstack-5.5.30-0\sym_prog\proj3_27\src\MeetingBundle\EventListener\ExceptionListener.php
<?php
namespace MeetingBundle\EventListener;
use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Router;
use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface;
use Symfony\Bundle\FrameworkBundle\Templating\EngineInterface;
//every time the Kernel throws the kernel.exception event, the function onKernelException() is called.
/* also must create service :
meeting.exception_listener:
class: MeetingBundle\EventListener\ExceptionListener
arguments: [#templating, #kernel, #router]
tags:
- { name: kernel.event_listener, event: kernel.exception, method: onKernelException }
*/
class ExceptionListener
{
protected $templating;
protected $kernel;
protected $router;
public function __construct( EngineInterface $templating, $kernel, Router $router)
{
$this->templating = $templating;
$this->kernel = $kernel;
$this->router = $router;
}
public function onKernelException(GetResponseForExceptionEvent $event)
{
$exception = $event->getException();
$request=$event->getRequest();
$referer = $event->getRequest()->headers->get('referer');
$msg="";
$excStr=$exception->__toString(); // returns string finally!
$bdup=strpos( $excStr , 'Integrity constraint violation: 1062 Duplicate entry' );
if($bdup) {
$msg=" This username is already taken. Choose another username. ";
}
if(strlen($msg)!=0) {
// flash messsages are displayed in layout.html
$request->getSession()
->getFlashBag()
->add('Error', $msg);
}
$response = new RedirectResponse($referer); // redirect to the error page
if ($exception instanceof HttpExceptionInterface) {
$response->setStatusCode($exception->getStatusCode());
$response->headers->replace($exception->getHeaders());
} else {
$response->setStatusCode(Response::HTTP_INTERNAL_SERVER_ERROR);
}
$event->setResponse($response);
}
}

How to create a complete custom form

how have I to create a custom Magento form? I don't need any extension or sample that mention the contact form. I mean that I need to understand how Magento with the modified Zend form handler works.
So the question is:
Does anybody have a code example for Magento created in a controller ?
<?php
class Mage_Contacts_IndexController extends Mage_Core_Controller_Front_Action
{
const XML_PATH_EMAIL_RECIPIENT = 'contacts/email/recipient_email';
const XML_PATH_EMAIL_SENDER = 'contacts/email/sender_email_identity';
const XML_PATH_EMAIL_TEMPLATE = 'contacts/email/email_template';
const XML_PATH_ENABLED = 'contacts/contacts/enabled';
public function preDispatch()
{
parent::preDispatch();
if( !Mage::getStoreConfigFlag(self::XML_PATH_ENABLED) ) {
$this->norouteAction();
}
}
public function indexAction()
{
$this->loadLayout();
$this->getLayout()->getBlock('contactForm')
->setFormAction( Mage::getUrl('*/*/post') );
$this->_initLayoutMessages('customer/session');
$this->_initLayoutMessages('catalog/session');
$this->renderLayout();
}
public function postAction()
{
$post = $this->getRequest()->getPost();
if ( $post ) {
$translate = Mage::getSingleton('core/translate');
/* #var $translate Mage_Core_Model_Translate */
$translate->setTranslateInline(false);
try {
$postObject = new Varien_Object();
$postObject->setData($post);
$error = false;
if (!Zend_Validate::is(trim($post['name']) , 'NotEmpty')) {
$error = true;
}
if (!Zend_Validate::is(trim($post['comment']) , 'NotEmpty')) {
$error = true;
}
if (!Zend_Validate::is(trim($post['email']), 'EmailAddress')) {
$error = true;
}
if (Zend_Validate::is(trim($post['hideit']), 'NotEmpty')) {
$error = true;
}
if ($error) {
throw new Exception();
}
$mailTemplate = Mage::getModel('core/email_template');
/* #var $mailTemplate Mage_Core_Model_Email_Template */
$mailTemplate->setDesignConfig(array('area' => 'frontend'))
->setReplyTo($post['email'])
->sendTransactional(
Mage::getStoreConfig(self::XML_PATH_EMAIL_TEMPLATE),
Mage::getStoreConfig(self::XML_PATH_EMAIL_SENDER),
Mage::getStoreConfig(self::XML_PATH_EMAIL_RECIPIENT),
null,
array('data' => $postObject)
);
if (!$mailTemplate->getSentSuccess()) {
throw new Exception();
}
$translate->setTranslateInline(true);
Mage::getSingleton('customer/session')->addSuccess(Mage::helper('contacts')->__('Your inquiry was submitted and will be responded to as soon as possible. Thank you for contacting us.'));
$this->_redirect('*/*/');
return;
} catch (Exception $e) {
$translate->setTranslateInline(true);
Mage::getSingleton('customer/session')->addError(Mage::helper('contacts')->__('Unable to submit your request. Please, try again later'));
$this->_redirect('*/*/');
return;
}
} else {
$this->_redirect('*/*/');
}
}
}