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

Refactored Source For ImportExport module, related to #7469 #9480

Conversation

IvanChepurnyi
Copy link
Contributor

@IvanChepurnyi IvanChepurnyi commented May 3, 2017

Description

The following pull request provides a refactored Import/Export source file parsing.
These are the major new features of this pull requests:

  • Developer can create custom parsers in any format by implementing \Magento\ImportExport\Model\Import\Source\FileParser\ParserInterface
  • Developer can create custom parser factories, so any stream or external resource can be feed as import. For adding new factory, developer needs to implement \Magento\ImportExport\Model\Import\Source\FileParser\ParserFactoryInterface and add it to \Magento\ImportExport\Model\Import\Source\FileParser\CompositeParserFactory as an argument in di.xml
  • Zip files are now properly implemented
  • Whole file parser logic is covered with tests and driven by TDD

Fixed Issues

#7468: CatalogImportExport doesn't support empty row values
* Added possiblity to specify "null" option for CsvParser, but this option must be passed into file creation factory
* Added extension points \Magento\ImportExport\Controller\Adminhtml\Import\Validate::getSourceAdapterOptions() and to \Magento\ImportExport\Model\Import::getSourceAdapterOptions() for override by thirdparty, as it is not yet possible to completely replace current creation logic without breaking code that is not covered with tests.

Manual testing scenarios

  1. Run integration tests with Import/Export related functionality
  2. Run unit tests with Import/Export related functionality

Contribution checklist

  • Pull request has a meaningful description of its purpose
  • All commits are accompanied by meaningful commit messages
  • All new or changed code is covered with unit/integration tests (if applicable)
  • All automated tests passed successfully (all builds on Travis CI are green)

@maghamed maghamed self-assigned this May 3, 2017
@maghamed maghamed self-requested a review May 3, 2017 15:09
@koenner01
Copy link
Contributor

Hey IvanChepurnyi, thanks for incorporating the fix for my reported issue.
I have just found a troublesome situation when using the empty value logic (#7468 (comment)).

Just wanted to let you know in case you might run into a similiar problem

@IvanChepurnyi
Copy link
Contributor Author

@koenner01 did you checked it with "null" option passed into CSV Parser Factory and then used this as an empty value for a special price?

Copy link
Contributor

@maghamed maghamed left a comment

Choose a reason for hiding this comment

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

My main concerns for this Pull Request:

  • Incorrect following of Backward Compatibility policies (new Interfaces should be added independently to legacy code). No need to mix up legacy and new implementation in one class.
  • Not proper work with Exceptions. Sometimes Exceptions substituted with FALSE value and vice versa.
  • Not proper Object design for factories and parser instantiation
  • Re-implemented some core functions responsible for work with filesystem
  • Lot of public getters are introduced just for testing purposes (violating object encapsulation)
  • All existing Unit tests are actually Integration ones, in terms of Magento 2

* @param $data
* @return array
*/
protected function getSourceAdapterOptions($data)
Copy link
Contributor

Choose a reason for hiding this comment

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

we don't recommend to use Inheritance Based API, so all the methods should be whether public or private

*
* @return array
*/
protected function getSourceAdapterOptions()
Copy link
Contributor

Choose a reason for hiding this comment

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

we don't recommend to use Inheritance Based API, so all the methods should be whether public or private

/** @var FileFactory */
private $fileSourceFactory;

public function __construct(FileFactory $fileSourceFactory)
Copy link
Contributor

Choose a reason for hiding this comment

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

doc block absent for this constructor

Copy link
Contributor Author

Choose a reason for hiding this comment

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

What do you see as a comment for a constructor?

Copy link
Contributor

Choose a reason for hiding this comment

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

DocBlock is not just comment, but specification of all input types.

@@ -25,29 +38,12 @@ class Adapter
* @return AbstractSource
*
* @throws \Magento\Framework\Exception\LocalizedException
* @deprecated
* @see Adapter::createSourceByPath()
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 better to avoid mixing up Deprecated logic and Newly created one in one class.
Thus, we recommend to introduce new Factory entity and mark it with @ api.
Current class to mark as @ deprecated.

Inject newly created factory as DI injection to Adapter class.
And make current class to proxy calls to newly created API

/** @var FileFactory */
private $fileSourceFactory;

public function __construct(FileFactory $fileSourceFactory)
Copy link
Contributor

Choose a reason for hiding this comment

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

Violation of BC policies, all the parameters should be optional (nullable)

$fileFactory->createFromFilePath('test.csv');
}

public function testGivenParserFactoryConfiguredWhenSourceIsCreatedByPathThenRightInstanceIsCreated()
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 not so easy to read this method name.
It's like 10 years ago when SMS cost a lot, you try to save space (140 symbols) for text not using spaces at all.

Copy link
Contributor Author

@IvanChepurnyi IvanChepurnyi Jul 14, 2017

Choose a reason for hiding this comment

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

Method name looks like this because "_" are prohibited by Magento code style guideline. Previous versions had "_" as space.

use Magento\ImportExport\Model\Import\Source\FileParser\ParserFactoryInterface;
use Magento\ImportExport\Model\Import\Source\FileParser\UnsupportedPathException;

class FakeParserFactory implements ParserFactoryInterface
Copy link
Contributor

Choose a reason for hiding this comment

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

We have so many Fake objects here, and we need to update their code updating code of the real objects as well

Currently, we don't use this approach for Unit testing. And definitely it needs separate approval from AC

Because for now we introduced additional entities to maintain. But why do we need that if we already have Integration tests?

@@ -0,0 +1 @@
column1|;column2;|column3
Copy link
Contributor

Choose a reason for hiding this comment

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

why do we need to use CSV files for Unit testing?

Integration tests are made for these purposes

Copy link
Contributor Author

Choose a reason for hiding this comment

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

There are no component level integration tests in Magento 2 repository and the one you are referring to requires to work with real database and other components enabled. However, this test case is quite isolated and does not leave any side effects visible to other test cases. Unit scope for this one is parsing a ZIP file, but integration test is more about testing integration of components versus just I/O operation.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Would love to get an advice how to overcome a problem of running fast "integration" test witout bootstrapping all database and other components.

namespace Magento\ImportExport\Model\Import\Source\FileParser;

/**
* File Parser Composite
Copy link
Contributor

Choose a reason for hiding this comment

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

should be marked as @ api , because used as an Extension Point

$resolvedArguments[] = $arguments[$parameter->getName()] ?? $parameter->getDefaultValue();
}

return $resolvedArguments;
Copy link
Contributor

Choose a reason for hiding this comment

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

when we provide an implementation of Fake objects, who and how will test this implementation?

For example, current function is 10 lines of code. How can we make sure that this code is safe to rely upon?

Copy link
Contributor Author

@IvanChepurnyi IvanChepurnyi Jul 14, 2017

Choose a reason for hiding this comment

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

I will add a test case for it, and also probably move it into framework, as FakeObjectManager must be available for other factory instantiation in the test harness as well.

Copy link
Contributor

@maghamed maghamed left a comment

Choose a reason for hiding this comment

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

My main concerns for this Pull Request:

  • Violation of Backward compatibility policies. No need to mix up the legacy (deprecated) code with newly created APIs. It's better to segregate classes.
  • There are many public getters added just for testing purposes and not used in code of business logic (violation of object encapsulation)
  • Not proper work with exceptions. Some of the exceptions are substituted with FALSE, and vice versa
  • Not proper Object Oriented design for ParserFactory instantiation
  • Some core functions for working with Filesystem are re-implemented on PHP level. Which is incorrect
  • All Unit tests looks like Integration tests in terms of Magento 2
  • Lot of Fake objects are introduced. These fake objects contain business logic, which is not covered with any kind of test. These fake objects should be also maintained in future

@maghamed maghamed self-assigned this Jul 17, 2017
@okorshenko okorshenko added this to the July 2017 milestone Jul 20, 2017
@okorshenko okorshenko removed this from the July 2017 milestone Aug 1, 2017
@okorshenko okorshenko modified the milestones: August 2017, July 2017 Aug 1, 2017
@ishakhsuvarov
Copy link
Contributor

@IvanChepurnyi @maghamed
Is there any activity on this PR at the moment or shall I close it for now?

@ishakhsuvarov
Copy link
Contributor

@IvanChepurnyi @maghamed I am closing this PR for now due to inactivity. Please reopen if you wish to continue work on it.
Thanks

@PieterCappelle
Copy link
Contributor

Hi @IvanChepurnyi, we are talking about this PR in the Magento2 Slack Channel. Is it possible to join this channel and join the channel #import_export. Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants