Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixed the support of Legacy classes using Console commands #15081

Closed
wants to merge 6 commits into from
Closed

Fixed the support of Legacy classes using Console commands #15081

wants to merge 6 commits into from

Conversation

mickaelandrieu
Copy link
Contributor

@mickaelandrieu mickaelandrieu commented Aug 12, 2019

Questions Answers
Branch? develop (but should be fixed asap)
Description? Creating Symfony Commands in PrestaShop is insanely error-prone! Let's try to add tests, and complete the Console enough to validate 90% of use cases.
Type? bugfix
Category? CO
BC breaks? nope!
Deprecations? yes
Fixed ticket? Fixes #14173
How to test? Tests are done, the build should be green.
<?php

namespace Fop\LatestProductsModule\Command;

use Product;
use PrestaShop\PrestaShop\Core\Console\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;

/**
 * This command display common information about a shop.
 */
final class LatestProductsCommand extends Command
{
    /**
     * {@inheritdoc}
     */
    protected function configure()
    {
        $this
            ->setName('fop:latest-products')
            ->setDescription('Displays Shop status')
            ->setHelp('This command allows you to display status of a shop')
        ;
    }

    /**
     * {@inheritdoc}
     */
    protected function execute(InputInterface $input, OutputInterface $output)
    {
        $products = Product::getNewProducts(1);

        $io = new SymfonyStyle($input, $output);
        $io->title('Legacy Latest Products listing');

        $io->table(
            ['ID', 'Name', 'Quantity', 'Price', 'Activated?'],
            $this->formatProductInformation($products)
        );
    }

    /**
     * @param array $products the list of the products
     *
     * @return array
     */
    private function formatProductInformation(array $products)
    {
        $productsInformation = [];
        /** @var Product $product */
        foreach ($products as $product) {
            $productsInformation[] = [
                $product['id_product'],
                $product['name'],
                $product['quantity'],
                $product['price'],
                $product['active'] ? '✔' : '✘',
            ];
        }

        return $productsInformation;
    }
}

output


This change is Reviewable

@mickaelandrieu mickaelandrieu requested a review from a team as a code owner August 12, 2019 14:58
@prestonBot prestonBot added develop Branch Improvement Type: Improvement labels Aug 12, 2019
@mickaelandrieu mickaelandrieu changed the title [WIP] Improved the support of PrestaShop commands with Legacy classes [Waiting for tests] Improved the support of PrestaShop commands with Legacy classes Aug 12, 2019
@mickaelandrieu mickaelandrieu removed the Improvement Type: Improvement label Aug 12, 2019
@mickaelandrieu
Copy link
Contributor Author

mickaelandrieu commented Aug 13, 2019

Hello @PrestaShop/prestashop-core-developers,

any chance to get this merged in the next patch version? 🙏

When do you plan to release 1.7.6.1?

@matks
Copy link
Contributor

matks commented Aug 13, 2019

any chance to get this merged in the next patch version? 🙏

I guess this is @eternoendless decision but if we follow our rules, this is neither a regression nor a critical bug 🤔 so it's not something we need to patch (=> would be shipped in a patch version), it's rather a nice improvement for next minor version

When do you plan to release 1.7.6.1?

We have only 1 issue in the 1.7.6 kanban (https://github.com/PrestaShop/PrestaShop/projects/4) so once the Kanban is empty (= every issue is in "done" column), we can process for the QA validation and then the release.
I guess it'll be easier in the end of August when QA team has a little more folks (right now a lot of them are in vacations) 😄

$this->legacyContext = $legacyContext;
$this->shopContext = $shopContext;

require_once $rootDir . '/../config/config.inc.php';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could be used for a LFI, please add a validation here

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you mean, validate that $rootDir will be a folder? in all cases, this file path will be dynamic.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe better to change this line https://github.com/PrestaShop/PrestaShop/blob/develop/autoload.php#L31 in config.inc.php to load the legacy context because of this https://github.com/PrestaShop/PrestaShop/blob/develop/bin/console#L16

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hello @PierreRambaud, I see what you mean but IMHO the comment on the related file ("Allow call of Legacy classes from classes in /src and /tests") doesn't work as expected.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is why it could be interesting to change the line and make it works

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure of the impacts as this file is also used in all contexts, I'd razer not rely on it and focus on what we need when we are in Console context.

How about a new file named autoload.php in console folder instead ?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file is only loaded in admin-dev/index.php and ./bin/console.
No need to create a new one to do the job its must do

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that the thing: I don't think we should use this file at all in Console context: I will remove this call and see what happens :)

/**
* {@inheritdoc}
*/
public function loadConsoleContext(InputInterface $input)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is InputInterface the right input arg for this command ? It looks like using HttpRequest as an input to me 🤔 maybe we should replace it with

Suggested change
public function loadConsoleContext(InputInterface $input)
public function loadConsoleContext($employeeId, $shopId, $shopGroupdId)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I need to add a new option I will have to break compatibility, and if I use scalar values I will have to validate data in this function when it's not its role (these options should be validated in the "interact" function of the commands.

$inputDefinition = $this->getDefinition();
$inputDefinition->addOption(new InputOption('employee', '-em', InputOption::VALUE_REQUIRED, 'Specify employee context (id).', null));

// @see MultiShopCommandListener BC compatible fix to display the options in the Console
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's nice you're trying to solve all issues at once 😄 but I think it's a big challenge
Maybe we should aim to fix the different contexts in the console with different PRs ? I suggest handling the multishop in a separate PR, I'm sure it's a little bomb 💣 that will require a lot of efforts to tackle

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it doesn't support multishop feature per see, it only displays the available options for each command :)

it's up to every command to handle or not these options ('id_shop' and 'id_shop_group') and it's probably a little 💣 I do agree

$this->setVersion(AppKernel::VERSION);

$inputDefinition = $this->getDefinition();
$inputDefinition->addOption(new InputOption('employee', '-em', InputOption::VALUE_REQUIRED, 'Specify employee context (id).', null));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is only needed for BO, what if the CLI is used for a FO-related processing ?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm thinking that maybe we should aim for BO-oriented CLI console and then a FO-oriented CLI console (separate concerns => separate envs) 🤔

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

except if I'm wrong you always have an employee set up, even in the Front Office :)

What kind of commands I can create that requires services available in FO?
Also, don't be fooled by the REQUIRED stuff: a CLI option is always optional 🤣

We need to cover more use cases, and I've already created 3 different commands in my module.

*
* @author Mickaël Andrieu <mickael.andrieu@prestashop.com>
*/
abstract class Command extends ContainerAwareCommand
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we improve the naming ? Command is a bit shy to express the fact that this is a "Symfony Command class for PrestaShop allowed to rely on legacy classes"

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I formerly named it "PrestaShopCommand", but as this class is part of PrestaShop only; I don't see the value to prefix the name of my class with PrestaShop.

I'm open to suggestions, what do you suggest?

@matks
Copy link
Contributor

matks commented Aug 13, 2019

@mickaelandrieu did a small review, it's great to see there's not so much to be done to fix the issue but I think it'll need extensive QA exploration for complex usecases like multishop

Nice job !

I did something a lot of time ago, dont know if it's related: I tried to make sure every SF Service we create is console-compliant
See #12127
but I surrendered when I saw the amount of work needed (#12127 (comment))

@mickaelandrieu
Copy link
Contributor Author

mickaelandrieu commented Aug 13, 2019

I did something a lot of time ago, dont know if it's related: I tried to make sure every SF Service we create is console-compliant

What we can do is add an extra validation pass to forbid every class that is not "namespaced" as an argument of a Symfony service: we should only rely on adapters or core classes.

Also, clean all core/prestashop classes to drop every "direct" call to object models: it's not that easy to do but in the long run, this will help you to remove object models (if you intent to ?).

Second extra rule, don't rely directly on the global state like "context" or "request".

This patch sounds complete, but I'm pretty sure such hacky use cases are not covered: I want to write more and more commands to try to break something 🗡 💥

@mickaelandrieu
Copy link
Contributor Author

mickaelandrieu commented Aug 13, 2019

ping @matks: looking at your PR I've contributed my own command to challenge the Console Context.

I've found some misses that I've fixed for now but I'll do it a better way soon.

check_container

As this won't be merged in 1.7.6.1 I'll probably close this pull request soon reduce the scope of this pull request to keep this fix so I can work in a community module instead. This way, so we get a chance to have more feedbacks then the core team will be free to backport the module into the Core and/or include the community module.

Thanks for your review, literally food for my brain 👍

@PierreRambaud PierreRambaud added the WIP Status: Work In Progress label Aug 19, 2019
/**
* {@inheritdoc}
*/
public function checkAccess()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since we are targeting 7.1+ you can type all your functions and parameters

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sadly, doing this will break the API as the former controller I extend doesn't type functions or arguments

@mickaelandrieu mickaelandrieu changed the title [Waiting for tests] Improved the support of PrestaShop commands with Legacy classes Improved the support of PrestaShop commands with Legacy classes Aug 28, 2019
@mickaelandrieu
Copy link
Contributor Author

Tests are here, I can add a lot of tests commands from my own module (that allow people to enjoy this feature starting 1.7.4 or 5).

WDYT?

*/
protected function buildContainer()
{
return SymfonyContainer::getInstance();
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this function is not used atm, but as the parent function is supposed to return a Container...

@mickaelandrieu mickaelandrieu changed the title Improved the support of PrestaShop commands with Legacy classes Fixed the support of Legacy classes using Console commands Aug 28, 2019
@mickaelandrieu mickaelandrieu removed the WIP Status: Work In Progress label Sep 17, 2019
@mickaelandrieu
Copy link
Contributor Author

Tests have been added 👍 , it's not in WIP anymore!

bin/console Outdated
@@ -12,8 +12,8 @@ use Symfony\Component\Debug\Debug;

set_time_limit(0);

require __DIR__.'/../vendor/autoload.php';
require_once __DIR__.'/../autoload.php';
require_once __DIR__.'/../vendor/autoload.php';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
require_once __DIR__.'/../vendor/autoload.php';

Already loaded in config.inc.php

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know but without it, I have the feeling it won't works.

Let me remove it and let's see if this file is required or not :)

@@ -6,7 +6,7 @@ services:

prestashop.adapter.cms_page_category.command_handler.abstract_cms_page_category_handler:
class: PrestaShop\PrestaShop\Adapter\CMS\PageCategory\CommandHandler\AbstractCmsPageCategoryHandler
abstract: true
abstract: true
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
abstract: true
abstract: true

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this file is not supposed to be there , i'll remove it

@mickaelandrieu
Copy link
Contributor Author

mickaelandrieu commented Sep 18, 2019

Hi @PierreRambaud,

comments addressed.

Thanks for review

And tests pass 🎉

@Progi1984 Progi1984 added WIP Status: Work In Progress and removed WIP Status: Work In Progress labels Dec 6, 2019
@mickaelandrieu mickaelandrieu deleted the dx/prestashop-command branch March 18, 2020 21:58
@mickaelandrieu mickaelandrieu restored the dx/prestashop-command branch May 12, 2020 14:56
@mickaelandrieu
Copy link
Contributor Author

mickaelandrieu commented May 12, 2020

:/ I had to restore this branch as #14173 is not fixed, but I wont have time to update/maintain it.

@Progi1984 Progi1984 removed this from the 1.7.7.0 milestone May 13, 2020
@mickaelandrieu mickaelandrieu deleted the dx/prestashop-command branch May 19, 2020 10:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
develop Branch
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Impossible to load Legacy classes in Console commands
6 participants