How to make pagination after merge two collections? - laravel

I use the standart method for pagination:
$ann = Ann::get()->orderBy('id', 'desc')->paginate($limit);
After I do merge $ann with another collection:
$ann = $ann->merge($ann_subscribed);
$ann = $ann->all();
In result I get $ann = $ann->all(); without pagination

1- add this to boot function in \app\Providers\AppServiceProvider
/**
* Paginate a standard Laravel Collection.
*
* #param int $perPage
* #param int $total
* #param int $page
* #param string $pageName
* #return array
*/
Collection::macro('paginate', function($perPage, $total = null, $page = null, $pageName = 'page') {
$page = $page ?: LengthAwarePaginator::resolveCurrentPage($pageName);
return new LengthAwarePaginator(
$this->forPage($page, $perPage),
$total ?: $this->count(),
$perPage,
$page,
[
'path' => LengthAwarePaginator::resolveCurrentPath(),
'pageName' => $pageName,
]
);
});
2-From hereafter for all collection you can paginate like this
$ann = Ann::orderByRaw('id','DESC')->get();
$ann_merged = $ann->merge($ann_subscribed);
$ann_merged ->paginate(5);

Related

pass an index to the method reduce() laravel

I have this function created to show a piechart but I need each element to show a different color. For this I have created an array with all the colors and I need in each iteration of the reduce() method to have an index to access the colors[i]. I have tried this way and it does not work. Any suggestion?
$i = 0;
$pieChartModel = $options->groupBy('survey_options_id')
->reduce(function (PieChartModel $pieChartModel, $data) use ($i) {
$type = $data->first()->survey_options_id;
$value = $data->sum('value');
// $color = "#" . substr(md5(rand()), 0, 6);
$NameOption = Survey_options::where('id', $type)->pluck('name');
return $pieChartModel->addSlice($NameOption, $value, $this->colors[$i]->hexa);
$i++;
}, (new PieChartModel())->setAnimated($this->firstRun)->setDataLabelsEnabled(true));
A problem I'm seeing in your code is how you're incrementing $i AFTER a return statement.
After taking a look at the source code for the reduce() function
/**
* Reduce the collection to a single value.
*
* #param callable $callback
* #param mixed $initial
* #return mixed
*/
public function reduce(callable $callback, $initial = null)
{
$result = $initial;
foreach ($this as $key => $value) {
$result = $callback($result, $value, $key);
}
return $result;
}
You should be able to use the key (or index) in the callback.
->reduce(function ($carry, $item, $key) { ... }, $initial)
->reduce(function (PieChartModel $pieChartModel, $data, $i) {
...
}, (new PieChartModel())->setAnimated($this->firstRun)->setDataLabelsEnabled(true))

Issue in Create Order Pragmatically with multiple products

I am trying to create order with multiple products using below code. code work fine, but one issue is occurring. I don't know why that adding more than one product create an order with just one product and all quantity summed to this.
<?php
namespace Magecomp\Cenpos\Controller\Index;
use Magento\Framework\App\Action;
use Magento\Framework\App\Filesystem\DirectoryList;
use Magento\Store\Model\StoreManagerInterface;
use Magento\Framework\Controller\ResultFactory;
class Display extends \Magento\Framework\App\Action\Action
{
protected $context;
protected $directory_list;
protected $cartRepositoryInterface;
protected $cartManagementInterface;
protected $_orderRepositoryInterface ;
/**
* #var \Magento\Sales\Model\Order\Email\Sender\OrderSender
*/
protected $orderSender;
/**
* #var \Magento\Checkout\Model\Session $checkoutSession
*/
protected $checkoutSession;
protected $_messageManager;
protected $_encryptor;
protected $_scopeConfig;
protected $logger;
public function __construct(
\Magento\Framework\App\Action\Context $context,
\Magento\Framework\App\Filesystem\DirectoryList $directory_list,
\Magento\Store\Model\StoreManagerInterface $storeManager,
\Magento\Catalog\Model\Product $product,
\Magento\Framework\Data\Form\FormKey $formkey,
\Magento\Quote\Model\QuoteFactory $quote,
\Magento\Quote\Model\QuoteManagement $quoteManagement,
\Magento\Customer\Model\CustomerFactory $customerFactory,
\Magento\Customer\Api\CustomerRepositoryInterface $customerRepository,
\Magento\Sales\Model\Service\OrderService $orderService,
\Magento\Customer\Model\Session $currentCustomer,
\Magento\Checkout\Model\Cart $cart,
\Magento\Quote\Api\CartRepositoryInterface $cartRepositoryInterface,
\Magento\Quote\Api\CartManagementInterface $cartManagementInterface,
\Magento\Checkout\Model\Session $checkoutSession,
\Magento\Sales\Model\Order\Email\Sender\OrderSender $orderSender,
\Magento\Framework\Encryption\EncryptorInterface $encryptor,
\Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig
//\Magento\Sales\Api\OrderRepositoryInterface $orderRepositoryInterface
) {
$this->directory_list = $directory_list;
$this->_storeManager = $storeManager;
$this->_product = $product;
$this->_formkey = $formkey;
$this->quote = $quote;
$this->quoteManagement = $quoteManagement;
$this->customerFactory = $customerFactory;
$this->customerRepository = $customerRepository;
$this->orderService = $orderService;
$this->_currentCustomer = $currentCustomer;
$this->_cart = $cart;
$this->cartRepositoryInterface = $cartRepositoryInterface;
$this->cartManagementInterface = $cartManagementInterface;
$this->checkoutSession = $checkoutSession;
$this->orderSender = $orderSender;
$this->_encryptor = $encryptor;
$this->_scopeConfig = $scopeConfig;
//$this->_orderRepositoryInterface = $orderRepositoryInterface;
$this->_messageManager = $context->getMessageManager();
parent::__construct($context);
}
public function saveShipping() {
if(isset($_POST['carrier_code']))
{
$_SESSION['carrier_code'] = $_POST['carrier_code'];
}
return true;
}
public function execute()
{
$objectManager = \Magento\Framework\App\ObjectManager::getInstance();
$cart = $objectManager->get('\Magento\Checkout\Model\Cart');
$shippingAddress = $cart->getQuote()->getShippingAddress();
$shippingAddressData = $shippingAddress->getData();
$Response = $_GET;
if($Response['message'] == "Approved" && $Response['result'] == "0") {
$store=$this->_storeManager->getStore();
$websiteId = $this->_storeManager->getStore()->getWebsiteId();
$customer=$this->customerFactory->create();
$customer->setWebsiteId($websiteId);
$customer->loadByEmail($shippingAddressData['email']);// load customet by email address
if(!$customer->getEntityId()){
//If not avilable then create this customer
$customer->setWebsiteId($websiteId)
->setStore($store)
->setFirstname($shippingAddressData['firstname'])
->setLastname($shippingAddressData['lastname'])
->setEmail($shippingAddressData['email'])
->setPassword($shippingAddressData['email']);
$customer->save();
$customer= $this->customerRepository->getById($customer->getEntityId());
}
//init the quote
$cart_id = $this->cartManagementInterface->createEmptyCart();
$cart = $this->cartRepositoryInterface->get($cart_id);
$cart->setStore($store);
// if you have already had the buyer id, you can load customer directly
$customer= $this->customerRepository->getById($customer->getEntityId());
$cart->setCurrency();
$cart->assignCustomer($customer); //Assign quote to customer
$productInfo = $this->_cart->getQuote()->getAllItems();
//add items in quote
foreach($productInfo as $item){
$product=$this->_product->load($item->getProductId());
$product->setPrice($item->getPrice());
$cart->addProduct(
$product,
intval($item->getQty())
);
}
$addressData = array(
'firstname' => $shippingAddressData['firstname'],
'lastname' => $shippingAddressData['lastname'],
'street' => $shippingAddressData['street'],
'city' => $shippingAddressData['city'],
'postcode' => $shippingAddressData['postcode'],
'telephone' => $shippingAddressData['telephone'],
'country_id' => $shippingAddressData['country_id'],
'region_id' => $shippingAddressData['region_id'],
'region' => $shippingAddressData['region'],
);
//set shipping and billing address
$quote = $this->quote->create();
$cart->getBillingAddress()->addData($addressData);
$cart->getShippingAddress()->addData($addressData);
if(isset($_SESSION['carrier_code'])) {
$shipping_method = $_SESSION['carrier_code'];
} else {
$session = $this->_objectManager->get('Magento\Checkout\Model\Session');
$shipping_method = $session->getQuote()->getShippingAddress()->getShippingMethod();
}
$shippingAddress = $cart->getShippingAddress();
$shippingAddress->setCollectShippingRates(true)
->collectShippingRates()
->setShippingMethod($shipping_method);
unset($_SESSION['carrier_code']);
$cart->setPaymentMethod('cenpos'); //payment method
//#todo insert a variable to affect the invetory
$cart->setInventoryProcessed(false);
$card_type_code = "VI";
$cart->getPayment()->importData(
[
'method' => 'cenpos',
'cc_type' => $card_type_code,
'cc_number' => '4893772408728522',
'cc_cid' => '341',
'cc_exp_month' => '02',
'cc_exp_year' => '2022'
]
);
// Collect total and save
$cart->collectTotals();
// Submit the quote and create the order
$cart->save();
$cart = $this->cartRepositoryInterface->get($cart->getId());
$order_id = $this->cartManagementInterface->placeOrder($cart->getId());
$objectManager = \Magento\Framework\App\ObjectManager::getInstance();
$orderRepository = $objectManager->create('Magento\Sales\Model\Order')->load($order_id);
$orderRepository->save();
$orderRepository->setEmailSent(true);
$this->checkoutSession->setForceOrderMailSentOnSuccess(true);
$this->orderSender->send($orderRepository, true);
$resultRedirect = $this->resultFactory->create(ResultFactory::TYPE_REDIRECT);
$resultRedirect->setUrl('http://m2gymtest.tpesonline.com/checkout/onepage/success');
return $resultRedirect;
}
}
}
Is there any problem in script? Or can it be server issue as the issue starts occurring after server changes.It was working properly before some days.
Use \Magento\Catalog\Model\ProductFactory $product instead of \Magento\Catalog\Model\Product $product in __construct() argument.
And Use
$product = $this->_product->create()->setStoreId($storeId)->load($item->getId());
to load the product instead of
$product=$this->_product->load($item->getProductId());
Hope this will help .

How to use pagination in collection fetched by sortBy and where operators?

I need pagination for my collection in which I have to apply lots of filters. But I'm unable to achieve this. I'm new to laravel so please show me the right way.
My controller:
public function index(Request $request)
{
$view = $request['view'] ? $request['view'] :'grid';
$purpose = $request['purpose'] ? $request['purpose'] : 'rent';
$sort = $request['sort'] ? $request['sort'] : 'asc';
$properties = $properties->where('purpose' , $purpose);
if($sort == 'asc');
$properties = $properties->sortBy('price');
else
$properties = $properties->sortByDesc('price');
$properties = $properties->paginate(5);
return view('frontend.properties.index', [ 'view'=>$view , 'properties' => $properties , 'request'=> $request->all() ]);
}
I have had this issue and in order to solve that, I have created a trait called PaginateCollection:
/*
* Paginate the Laravel Collection before and/or after filtering.
*
*/
trait PaginateCollection
{
/**
* Paginate the collection.
*
* #param \Illuminate\Support\Collection|\Illuminate\Database\Eloquent\Collection $collection
* #param integer $perPage
* #param integer $currentPage
* #return \Illuminate\Pagination\LengthAwarePaginator
*/
public function paginate($collection, $perPage = 10, $currentPage = 1)
{
$offSet = ($currentPage * $perPage) - $perPage;
$otherParams = [
'path' => request()->url(),
'query' => request()->query()
];
return new LengthAwarePaginator(
$collection->forPage(Paginator::resolveCurrentPage() , $perPage),
$collection->count(),
$perPage,
Paginator::resolveCurrentPage(),
$otherParams
);
}
}
Perhaps, this should help you out.

Can't get POST data with AJAX

I would like to show 4 objects in a page, with a "load more" button which show 4 more object each time we click.
I try to adapt a PHP script which works(tested) to Symfony.
The problem is that I can't get the POST data (a page number) in my Symfony function, even if I can see it in the chrome developer toolbar...
My controller:
<?php
/**
* Content controller.
*
* #Route("content")
*/
class ContentController extends Controller
{
/**
* Lists all software.
*
* #Route("/software", name="content_software")
* #Method({"POST", "GET"})
*/
public function softwareAction(Request $request)
{
if ($request->request->get('page')){
$page_number = filter_var($_POST["page"], FILTER_SANITIZE_NUMBER_INT,
FILTER_FLAG_STRIP_HIGH);
$item_per_page = 4;
$position = (($page_number-1) * $item_per_page);
$contents = $this->getRepo()->findBy(array(),null,$item_per_page,$position);
}
else
{
$contents = "didn't work";
}
return $this->render('content/index.html.twig', array(
'contents' => $contents
));
}
}
index.html.twig :
{% extends 'loicCoreBundle::Default/layout.html.twig' %}
{% block body %}
{{ dump(contents) }}
<script type="text/javascript">
var track_page = 1; //track user click as page number, right now page number is 1
load_contents(track_page); //load content
$("#load_more_button").click(function (e) { //user clicks on button
track_page++; //page number increment everytime user clicks load button
load_contents(track_page); //load content
});
//Ajax load function
function load_contents(track_page){
$.post( "{{ path('content_software') }}", {'page': track_page}, function(data){
if(data.trim().length == 0){
//display text and disable load button if nothing to load
$("#load_more_button").text("No more records!").prop("disabled", true);
}
});
}
</script>
{% endblock %}
I'm not sure where your errors are coming from, I've done a similar test which just works (no problems with $request->request->get()).
You are however loading a full template (index.html) for each sub request as well. Usually you want to separate calls like this into api like methods, however for simple things its a bit silly.
Here is an expanded/ updated version of what I tested, I avoided post data all together and just used the method as switch. This worked fine so try and figure out where you went wrong using this as reflection (or whatever you like to do with it). Note this uses a simple PHP range array for test data, not entities but it should remain the same principle.
Controller
/**
* #Route(
* "software/{page}/{limit}",
* name="content_software",
* requirements = {
* "page": "[1-9]\d*",
* "limit": "[1-9]\d*"
* }
* )
*/
public function softwareAction(Request $request, $page = 1, $limit = 4) {
if ($request->isMethod('POST')) {
// replace these two lines with database logic (SELECT & LIMIT)
$start = ($page - 1) * $limit;
$items = array_slice(range(1, 10), $start, $limit); // Just using a simple item array [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] as test data
$content = '';
foreach ($items as $item) {
$content .= $this->get('twig')->render('someItemTemplate.html.twig', ['item' => $item]);
}
return new Response($content);
} else {
// alternatively you can send out the default items here for the first get request
// and use the same item template above with {% embed %} to render them in this template
return $this->render('someTemplate.html.twig');
}
}
someTemplate.html.twig
<html>
<head>
<title>Cake or death?</title>
</head>
<body>
<ul id="put-the-things-here"></ul>
<button id="next_please">Ehh cake please!</button>
<script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
<script>
var pageTracker = 1,
$next = $("#next_please"),
$target = $('#put-the-things-here');
load_contents(pageTracker);
$next.click(function (e) {
load_contents(++pageTracker);
});
function load_contents(page) {
// using post just for the request method (page is in the url)
$.post("{{ path('content_software') }}/" + page,
function (data) {
if (data) {
$target.append(data);
} else {
$target.append('<li>We are out of cake.</li>');
$next.attr('disabled', true);
}
}
);
}
</script>
</body>
</html>
someItemTemplate.twig
<li>Cake: {{ item }}</li>
try this:
$request->request->get('page')
Instead of this:
$request->request->has('page')
If it doesn't work try to:
var_dump($request->request->all());
And check the variables
I think too the problem comes from routes.
Error message when I use only "POST" method :
"No route found for "GET /content/software": Method Not Allowed (Allow: POST, DELETE)".
Because when I arrive on my page by clicking a link , I arrive with a GET method.
However, when I click on my "load more" button the AJAX works and I can see in my symfony debugbar that I get POST variable:
The problem is when I first arrive on my page I think.
#Jenne van der Meer: Thank you but I would like not to use GET parameters.
I add my full controller code, in case of:
/**
* Content controller.
*
* #Route("content")
*/
class ContentController extends Controller
{
public function getRepo(){
$em = $this->getDoctrine()->getManager();
$repo = $em->getRepository('loicContentBundle:Content');
return $repo;
}
// private $theRepo = getDoctrine()->getManager()->getRepository('loicContentBundle:Content');
/**
* Lists all content entities.
*
* #Route("/", name="content_index")
* #Method("GET") */
public function indexAction(Request $request)
{
$contents = $this->getRepo()->findAll();
$this->denyAccessUnlessGranted('ROLE_USER', null, 'Unable to access this page!');
$formFilter = $this->createFormBuilder()
->add('_', EntityType::class,array(
'class' => 'loicFilterBundle:Filter',
'multiple' => true,
'expanded' => true,
'choice_label' => function($value) {
return ($value->getName());
},
))
->add('Appliquer filtres', SubmitType::class)
->getForm();
$formFilter->handleRequest($request);
$data = '';
if ($formFilter->isSubmitted() && $formFilter->isValid()) {
$data = $formFilter->getData();
$data = $data['_']->toArray();
$contents = $this->getRepo()->findAll();
}
else
{$contents = $this->getRepo()->findAll();
}
return $this->render('content/index.html.twig', array(
'contents' => $contents,'formFilter' => $formFilter->createView(),'request' => $request
));
}
public function contentAction($categoryId)
{
$contents= $this->getRepo()->findBy(
array('contentCategorycontentCategory' => $categoryId),
null,
4
);
return $contents;
}
/**
* Lists all software.
*
* #Route("/software", name="content_software")
*/
public function softwareAction(Request $request)
{
var_dump($request->request->all());
$bla = $request->request->get('page');
if ($request->request->get('page')){
$page_number = filter_var($_POST["page"], FILTER_SANITIZE_NUMBER_INT,
FILTER_FLAG_STRIP_HIGH);
$item_per_page = 4;
$position = (($page_number-1) * $item_per_page);
$contents = $this->getRepo()->findBy(array(),null,$item_per_page,$position);
}
else
{
$contents = "didn't work";
}
return $this->render('content/index.html.twig', array(
'contents' => $contents,'bla' => $bla
));
}
/**
* Lists all videos.
*
* #Route("/videos", name="content_videos")
* #Method("GET")
*/
public function videoAction()
{
$contents = $this->contentAction(5);
return $this->render('content/index.html.twig', array(
'contents' => $contents,
));
}
/**
* Lists all testimonies.
*
* #Route("/testimonies", name="content_testimonies")
* #Method("GET")
*/
public function testimoniesAction()
{
$contents = $this->contentAction(8);
return $this->render('content/index.html.twig', array(
'contents' => $contents,
));
}
/**
* Lists all whiteBooks.
*
* #Route("/whiteBooks", name="content_whiteBooks")
* #Method("GET")
*/
public function whiteBooksAction()
{
$contents = $this->contentAction(3);
return $this->render('content/index.html.twig', array(
'contents' => $contents,
));
}
/**
* Lists all actuality.
*
* #Route("/actuality", name="content_actuality")
* #Method("GET")
*/
public function actualityAction()
{
$contents = $this->contentAction(6);
return $this->render('content/index.html.twig', array(
'contents' => $contents,
));
}
/**
* Lists all webinar.
*
* #Route("/webinar", name="content_webinar")
* #Method("GET")
*/
public function webinarAction()
{
$contents = $this->contentAction(4);
return $this->render('content/index.html.twig', array(
'contents' => $contents,
));
}
/**
* Lists all blog posts.
*
* #Route("/blog", name="content_blog")
* #Method("GET")
*/
public function blogAction()
{
$contents = $this->contentAction(7);
return $this->render('content/index.html.twig', array(
'contents' => $contents,
));
}
/**
* Creates a new content entity.
*
* #Route("/new", name="content_new")
* #Method({"GET", "POST"})
*/
public function newAction(Request $request)
{
$em = $this->getDoctrine()->getManager();
$content = new Content();
$form = $this->createForm('loic\ContentBundle\Form\ContentType', $content);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->persist($content);
$em->flush($content);
return $this->redirectToRoute('content_show', array('id' => $content->getIdcontent()));
}
return $this->render('content/new.html.twig', array(
'content' => $content,
'form' => $form->createView(),
));
}
/**
* Displays a form to edit an existing content entity.
*
* #Route("/{id}/edit", name="content_edit")
* #Method({"GET", "POST"})
*/
public function editAction(Request $request, Content $content)
{
$deleteForm = $this->createDeleteForm($content);
$editForm = $this->createForm('loic\ContentBundle\Form\ContentType', $content);
$editForm->handleRequest($request);
if ($editForm->isSubmitted() && $editForm->isValid()) {
$this->getDoctrine()->getManager()->flush();
return $this->redirectToRoute('content_edit', array('id' => $content->getIdcontent()));
}
return $this->render('content/edit.html.twig', array(
'content' => $content,
'edit_form' => $editForm->createView(),
'delete_form' => $deleteForm->createView(),
));
}
/**
* Deletes a content entity.
*
* #Route("/{id}", name="content_delete")
* #Method("DELETE")
*/
public function deleteAction(Request $request, Content $content)
{
$form = $this->createDeleteForm($content);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->remove($content);
$em->flush();
}
return $this->redirectToRoute('content_index');
}
/**
* Creates a form to delete a content entity.
*
* #param Content $content The content entity
*
* #return \Symfony\Component\Form\Form The form
*/
private function createDeleteForm(Content $content)
{
return $this->createFormBuilder()
->setAction($this->generateUrl('content_delete', array('id' => $content->getIdcontent())))
->setMethod('DELETE')
->getForm()
;
}
}
My Bundle/Resources/config/routing.yml file is empty.

How to create a paginator?

I've checked out the rather thin docs, but still unsure how to do this.
I have a collection. I wish to manually create a paginator.
I think I have to do something like, in my controller:
new \Illuminate\Pagination\LengthAwarePaginator()
But, what params do I need and do I need to slice the collection? Also how do I then display the 'links' in my view?
Could someone post a simple example how to create a paginator?
Please note, I don't want to paginate eloquent, eg. User::paginate(10);
Take a look at the Illuminate\Eloquent\Builder::paginate method for an example on how to create one.
A simple example of doing one using an eloquent model to pull out the results etc:
$page = 1; // You could get this from the request using request()->page
$perPage = 15;
$total = Product::count();
$items = Product::take($perPage)->offset(($page - 1) * $perPage)->get();
$paginator = new LengthAwarePaginator(
$items, $total, $perPage, $page
);
The first parameter accepts the results to display on the page that you're on
the second is the total number of results (The total number of items you're paginating, not the total number of items you're displaying on that page)
the third is the number per page you want to display
the fourth is the page that you're on.
You can pass in extra options as a fifth parameter if you want to customise things as well.
The links you should just be able to generate using the ->render() or ->links() method on the paginator as you would if you used Model::paginate()
With an existing collection of items you could do this:
$page = 1;
$perPage = 15;
$total = $collection->count();
$items = $collection->slice(($page - 1) * $perPage, $perPage);
$paginator = new LengthAwarePaginator(
$items, $total, $perPage, $page
);
You can create a Paginator like this:
$page = request()->get('page'); // By default LengthAwarePaginator does this automatically.
$collection = collect(...array...);
$total = $collection->count();
$perPage = 10;
$paginatedCollection = new \Illuminate\Pagination\LengthAwarePaginator(
$collection,
$total,
$perPage,
$page
);
According to the source code for LengthAwarePaginator (constructor)
public function __construct($items, $total, $perPage, $currentPage = null, array $options = [])
{
foreach ($options as $key => $value) {
$this->{$key} = $value;
}
$this->total = $total;
$this->perPage = $perPage;
$this->lastPage = (int) ceil($total / $perPage);
$this->path = $this->path != '/' ? rtrim($this->path, '/') : $this->path;
$this->currentPage = $this->setCurrentPage($currentPage, $this->pageName);
$this->items = $items instanceof Collection ? $items : Collection::make($items);
}
See more about LengthAwarePaginator
To display links in the view:
$paginatedCollection->links();
Hope this helps!

Resources