How to retreave New Arrivals in another view?

Help for integrating the Laravel package
Forum rules
Always add your Laravel, Aimeos and PHP version as well as your environment (Linux/Mac/Win)
Spam and unrelated posts will be removed immediately!
Sabir_Ali
Posts: 12
Joined: 12 Feb 2024, 06:43

How to retreave New Arrivals in another view?

Post by Sabir_Ali » 22 Feb 2024, 08:09

PHP: 8.1.2-1ubuntu2.14
Laravel Framework: 10.43.0
System: Ubuntu Gnu Linux 22.04

We installed another theme and trying to customize it to work with the platform. My task is to get the New Arrivals list in main page (PHP file) and show in a view specified by the theme.

How should I approach this problem correctly?
1. Do I have to know where is the logic lies of this "query" or the place where this logic is going? If Yes, where is the logic of the New Arrivals are placed (if exist)?
2. Or there is another more simple approach to do it using an abstract layer, created by Aimeos for such type tasks?
3. Or I have to use a mixed way using a custom manager or a controller, for example?

User avatar
aimeos
Administrator
Posts: 7895
Joined: 01 Jan 1970, 00:00

Re: How to retreave New Arrivals in another view?

Post by aimeos » 25 Feb 2024, 11:04

There's currently not specialized component to display the latest products but you can use the catalog/list component and pass f_sort=-ctime as Parameter.

If the list should be manageable via the CMS module, you need to implement a block in JS for GrapesJS like here:
- https://github.com/aimeos/ai-cms-grapes ... #L347-L356
- https://github.com/aimeos/ai-cms-grapes ... #L570-L663
Professional support and custom implementation are available at Aimeos.com
If you like Aimeos, Image give us a star

Sabir_Ali
Posts: 12
Joined: 12 Feb 2024, 06:43

Re: How to retreave New Arrivals in another view?

Post by Sabir_Ali » 26 Feb 2024, 08:12

Thank you for response.
No, I don't need a manageable list via CMS module. My goal is very simple right now. I just need to get a product list by a "controller" or from context to make a filter on it (for example by date). And this list will be something, that we can call a "New Arrivals".

But while You answer, I created a new controller (in app/Http/Controllers/MainPageController.php) for main page, which is actually a back end, that uses another class (in app/Http/Controllers/Frontend/NewArrivalsCustom.php) where the search is going on. And a Service (in app/Services/ProductService.php) which calls a product Item's methods to get some data. And I get some basic data, like label for instance. But I don't get media data now, like images. And I think this data I have to get from additional tables, 'mshop_media' or something like that.

I'm not sure this is good way to get products data in the main page. But I'm working on it.

This is the Controller code snippet:

Code: Select all

class MainPageController extends Controller
{
    protected ProductService $productService;

    public function __construct(ProductService $productService)
    {
        $this->productService = $productService;
    }

    public function showMainPage()
    {
        $context = app('aimeos.context')->get(false);
        $newArrivalsController = new NewArrivalsCustom($context);

        $newArrivals = $newArrivalsController->getNewArrivals();

        foreach($newArrivals as $product) {
            $product->label = $this->productService->getLabel($product);
            // other data
        }

        // Passing variables to the view
        return view('myext::catalog.home', [
            'newArrivals' => $newArrivals,
            //  other variables
        ]);

    }
}
This is the helper class:

Code: Select all

class NewArrivalsCustom extends Standard
{
    public function __construct(\Aimeos\MShop\ContextIface $context)
    {
        parent::__construct($context);
        $this->context = $context;
    }
    
    public function getNewArrivals(): \Aimeos\Map
    {
        $indexManager = \Aimeos\MShop::create($this->context, 'index');

        $search = $indexManager->filter();

        // Set the conditions for "new" products
        // $search->setConditions($search->compare('>=', 'product.ctime', date('Y-m-d H:i:s', strtotime('-30 days'))));
        $search->setConditions($search->compare('>', 'product.id', 0));

        $search->setSortations([$search->sort('-', 'product.ctime')]);
        $search->slice(0, 10);

        return $indexManager->search($search);
    }
}
This is a ProductService class code snippet:

Code: Select all

class ProductService
{
    protected $context;

    public function __construct(\Aimeos\MShop\ContextIface $context)
    {
        $this->context = $context;
    }

    public function getLabel($productItem)
    {
        return $productItem->getLabel();
    }

    public function getName($productItem)
    {
        return $productItem->getName();
    }
}
I'm not an expert in Front-end and I try do it by standard Laravel way (as I think). If you have any advice, I'll be very grateful.

User avatar
aimeos
Administrator
Posts: 7895
Joined: 01 Jan 1970, 00:00

Re: How to retreave New Arrivals in another view?

Post by aimeos » 27 Feb 2024, 10:39

All your code should go into the MainPageController.php to make it simple.
You can get related items to products like images, prices and texts by using:

Code: Select all

        $indexManager = \Aimeos\MShop::create($this->context, 'index');

        $search = $indexManager->filter( true )
        	->add('product.ctime', '>=', date('Y-m-d H:i:s', time() - 86400 * 30))
        	->order('-product.ctime')
        	->slice(0, 10);

        return $indexManager->search($search, ['media', 'price', 'text']);
Professional support and custom implementation are available at Aimeos.com
If you like Aimeos, Image give us a star

Sabir_Ali
Posts: 12
Joined: 12 Feb 2024, 06:43

Re: How to retreave New Arrivals in another view?

Post by Sabir_Ali » 01 Mar 2024, 11:53

I solved my issue and I want to share how I did it.
The main problem was that the main page has been written in PHP (I mean it is not blade file) and has a complex slider. But the part of code where I iterate the newArrivals was included into blade file. And I couldn't make these two files work together. Because to make my blade file see the data I created my own controller. And that controller was called from my custom Route in the /routes/web.php. I spent a lot of time in trying merge them together. So. This is the part of slider file where "this" is the Aimeos\Base\View\Standard class:

Code: Select all

<?php if( isset( $this->homeTree ) && !(
        $this->homeTree->getRefItems( 'media', 'stage', 'default' )->isEmpty()
        && $this->homeTree->getChildren()->getRefItems( 'media', 'stage', 'default' )->collapse( 1 )->isEmpty()
    ) ) : ?>
...
I solved this problem by creating Laravel View Composer. I created app/Http/ViewComposers/NewArrivalsComposer.php file, where I get the newArrivals:

Code: Select all

use Aimeos\MShop\Exception;
use App\Services\NewArrivalsFilter;
use App\Services\ProductService;
use Illuminate\View\View;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;

class NewArrivalsComposer
{
    public function __construct(private readonly ProductService $productService) { }

    public function compose(View $view): void
    {
        $context = app('aimeos.context')->get(false);
        $newArrivalsController = new NewArrivalsFilter($context);

        $newArrivals = $newArrivalsController->getNewArrivals();

        foreach($newArrivals as $product) {
            $product->label = $this->productService->getLabel($product);
            $product->price = $this->productService->getPrice($product);
        }

        $view->with('newArrivals', $newArrivals);
    }
}
Where app/Services/NewArrivalsFilter.php is:

Code: Select all

use Aimeos\Controller\Frontend\Catalog\Standard;
use Aimeos\MShop;
use Aimeos\MShop\ContextIface;
use Aimeos\MShop\Exception;

class NewArrivalsFilter extends Standard
{
    public function __construct(private readonly ContextIface $context)
    {
        parent::__construct($context);
    }

    public function getNewArrivals(): \Aimeos\Map
    {
        $indexManager = MShop::create($this->context, 'index');
        $search = $indexManager->filter();

        // Sort descending by the creation time.
        $search->setSortations([$search->sort('-','product.ctime' )]);

        // Show only the first 10 new arrivals from the last search result.
        $search->slice(0, 10);

        $productIds = $indexManager->search($search)->keys()->toArray();
        $productManager = MShop::create($this->context, 'product');
        $products = $productManager->search($productManager->filter(true), ['media', 'price', 'text']);

        return $products->filter(function ($item) use ($productIds) {
            return in_array($item->getId(), $productIds);
        });
    }
}
And app/Services/ProductService.php is:

Code: Select all

class ProductService
{
    public function getLabel(mixed $productItem)
    {
        return $productItem->getLabel();
    }

    public function getName(mixed $productItem)
    {
        return $productItem->getName();
    }

    public function getPrice(mixed $productItem): ?string
    {
        $price = $productItem->getRefItems('price', 'default', 'default')->first();

        if ($price) {
            return sprintf('%s %s', $price->getValue(), $price->getCurrencyId());
        }

        return null;
    }
}
Then I register the View Composer in boot() method of the package Service Provider:

Code: Select all

View::composer(
            'our-package::catalog.parts.content',
            NewArrivalsComposer::class
        );
And our blade file packages/our-package/views/catalog/parts/content.blade.php shows the newArrivals:

Code: Select all

<div class="tab-content jump">
            <div class="tab-pane active" id="home1">
                <div class="custom-row">
                    @foreach ($newArrivals as $product)
                        <div class="custom-col-5 mb-30">
                            <div class="devita-product-2 mrg-inherit devita-product-red">
                                <div class="product-img">
                                    <div class="product-img-slider">
                                        @php
                                            $mediaItem = $product->getRefItems('media', 'default', 'default')->first();
                                        @endphp

                                        @if ($mediaItem)
                                            <a href="#">
                                                <img src="{{ asset($mediaItem->getPreview()) }}" alt="{{ $mediaItem->getProperties('title')->first() }}">
                                                <span>{{ $product->price }}</span>
                                            </a>
                                        @else
...
                                        @endif
                                    </div>
                                    @if($product->getLabel())
                                        <span>{{ $product->label }}</span>
                                    @endif
                                </div>
                            </div>
                        </div>
                    @endforeach
                </div>
            </div>
Maybe I created extra files. But architecturally it looks normal.

Post Reply