Post on 26-Jul-2020
transcript
James CowieSoftware Engineer
Session Digital
@Jcowie
Getting ready for Magento 2
• How to prepare for a new e-
commerce system
Whats changed since Magento 1 ?
PHP has changed
PHP since Magento 1
• Composer - 2012
• Namespaces - PHP 5.3.0 - 2009
• Traits - PHP 5.3.0 - 2009
• Generators - PHP 5.5.0 - 2013
• Better Interface support PHP 5.3.9 2009
• Type Hinting - PHP 5.4 - 2012
• ….
The world of engineering has changed
Software Engineering
• Server Architecture
• Cloud
• Docker
• VPS
• Software Architecture within PHP
• TDD
• PHPSpec - 2011
• BDD
• Behat - 2011
• DDD
Installing Magento
How did we install Magento 1
• Large scale bundled installations per versions.
Along came composer
Installing Magento 2 with composer
composer create-project--stability=beta--no-installmagento/project-community-editionM2Test
Whats this created
{"name": "magento/project-community-edition","type": "project","require": {
"magento/product-community-edition": "0.74.0-beta12"
},"require-dev": {}
}
But wait there is more composer offers
More Composer
• Packagist + packages.magento.com
• Package versioning
• Dependency Management
Show me the use case !
composer require "league/period"
1 /** 2 * @var League\Period\Period; 3 */4 protected $_datePeriod;5 6 /** 7 * @param \League\Period\Period; $datePeriod 8 */9 public function __construct(\League\Period\Period $datePeriod)
10 {11 $this->_datePeriod = $datePeriod;12 }
Composer 101
Versioning In Composer
Composer 101
Exact version: “1.4.2″, “v1.4.2″.
"magento/product-community-edition": “1.0.1”
Composer 101
Ranges: >=1.0, <2.0,
"magento/product-community-edition": “>=1.0, <2”
Composer 101
Wildcard: “1.0.*”,
“1.*”
"magento/product-community-edition": “1.*”
"magento/product-community-edition": “1.0.*”
Composer 101
Next Significant Release: “~1.2″ is equivalent to “>=1.2,<2.0″.
"magento/product-community-edition": “~1.2”
A note on semver
Decoupling modules
Better Module Architecture
We can and should apply best software practice to Magento
Benefits of decoupling modules ?
• Clean Code
• Reusable packages
• Testable
• Easier to read
• Easier to maintain
Yea but in Magento 1 we could not fully do this..
Decoupling in Magento 1
• No Dependency Injection container.
• Mage god class
• Hard to test
• Hard to decouple logic
Dependency Injection in Magento 2
public function __construct(\Magento\Framework\App\Action\Context $context,\Magento\Catalog\Model\Design $catalogDesign,\Magento\Catalog\Model\Session $catalogSession,\Magento\Framework\Registry $coreRegistry,\Magento\Store\Model\StoreManagerInterface $storeManager,\Magento\CatalogUrlRewrite\Model\CategoryUrlPathGenerator $categoryUrlPathGenerator,PageFactory $resultPageFactory,\Magento\Framework\Controller\Result\ForwardFactory $resultForwardFactory,Resolver $layerResolver,CategoryRepositoryInterface $categoryRepository\Magento\Framework\App\Action\Context $context,\Magento\Catalog\Model\Design $catalogDesign,\Magento\Catalog\Model\Session $catalogSession,\Magento\Framework\Registry $coreRegistry,\Magento\Store\Model\StoreManagerInterface $storeManager,\Magento\CatalogUrlRewrite\Model\CategoryUrlPathGenerator
public function __construct(\Magento\Framework\App\Action\Context $context,\Magento\Catalog\Model\Design $catalogDesign,\Magento\Catalog\Model\Session $catalogSession,\Magento\Framework\Registry $coreRegistry,\Magento\Store\Model\StoreManagerInterface $storeManager,\Magento\CatalogUrlRewrite\Model\CategoryUrlPathGenerator $categoryUrlPathGenerator,PageFactory $resultPageFactory,\Magento\Framework\Controller\Result\ForwardFactory $resultForwardFactory,Resolver $layerResolver,CategoryRepositoryInterface $categoryRepository\Magento\Framework\App\Action\Context $context,\Magento\Catalog\Model\Design $catalogDesign,\Magento\Catalog\Model\Session $catalogSession,\Magento\Framework\Registry $coreRegistry,\Magento\Store\Model\StoreManagerInterface $storeManager,\Magento\CatalogUrlRewrite\Model\CategoryUrlPathGenerator
Code Smell
Information on DI
• Dependency Injection replaces Mage:: god class
• Dependency Injection can be overused.
• Dependency Injection enables composition.
How we manage dependencies without Injection
1 <?php2 class Sample3 {4 protected $logger;5 6 public function doSomething()7 {8 $this->logger = new \Logger();9 $logger->doSomething();10 }11 }
How we manage dependencies without Injection
1 <?php2 class Sample3 {4 protected $logger;5 6 public function doSomething()7 {8 $this->logger = new \Logger();9 $logger->doSomething();10 }11 }
Basic Dependency Injection
1 <?php2 class SampleDi {3 protected $logger;4 public function __construct(\Logger $logger) {5 $this->logger = $logger;6 }7 8 public function doSomething() {9 $this->logger->doSomething();10 }11 }
Basic Dependency Injection
1 <?php2 class SampleDi {3 protected $logger;4 public function __construct(\Logger $logger) {5 $this->logger = $logger;6 }7 8 public function doSomething() {9 $this->logger->doSomething();10 }11 }
Basic Dependency Injection
1 <?php2 class SampleDi {3 protected $logger;4 public function __construct(\Logger $logger) {5 $this->logger = $logger;6 }7 8 public function doSomething() {9 $this->logger->doSomething();10 }11 }
What are the benefits of DI ?
• Creating a new instance of logger is removed from the class.
• Concrete implementation of Logger can be swapped out via
container configuration
• When running tests we can Mock the dependency
How does this look within Magento 2
/** * @param \Magento\Framework\View\Element\Context $context */public function __construct(
\Magento\Framework\View\Element\Context$context
) {parent::__construct($context, $data);
}
DI Continued
Its not only Objects that can be injected.
<type name="Magento\Cms\Model\Wysiwyg\Images\Storage"><arguments><argument name="extensions" xsi:type="array">
<item name="allowed" xsi:type="array"><item name="jpg" xsi:type="number">1</item><item name="jpeg" xsi:type="number">1</item><item name="png" xsi:type="number">1</item><item name="gif" xsi:type="number">1</item></item>
</argument></arguments>
…
<type name="Magento\Cms\Model\Wysiwyg\Images\Storage"><arguments><argument name="extensions" xsi:type="array">
<item name="allowed" xsi:type="array"><item name="jpg" xsi:type="number">1</item><item name="jpeg" xsi:type="number">1</item><item name="png" xsi:type="number">1</item><item name="gif" xsi:type="number">1</item></item>
</argument></arguments>
…
<type name="Magento\Cms\Model\Wysiwyg\Images\Storage"><arguments><argument name="extensions" xsi:type="array">
<item name="allowed" xsi:type="array"><item name="jpg" xsi:type="number">1</item><item name="jpeg" xsi:type="number">1</item><item name="png" xsi:type="number">1</item><item name="gif" xsi:type="number">1</item></item>
</argument></arguments>
…
<type name="Magento\Cms\Model\Wysiwyg\Images\Storage"><arguments><argument name="extensions" xsi:type="array">
<item name="allowed" xsi:type="array"><item name="jpg" xsi:type="number">1</item><item name="jpeg" xsi:type="number">1</item><item name="png" xsi:type="number">1</item><item name="gif" xsi:type="number">1</item></item>
</argument></arguments>
…
protected $_extensions;
public function __construct(array $extensions = []
) {$this->_extensions = $extensions;
}
$allowed = $this->_extensions["{$type}_allowed"];
Inversion of Control
• Separating instantiation of objects from the object
• Easier to test
• Aids with Separation of concerns
How can we test this ?
function it_should_create_a_new_cached_image($filesystem){
$filesystem->beADoubleOf(\Magento\Framework\Filesystem $fileSystem);
$this->createCachedFile($filesystem)->shouldReturnTrue();
}
Closing thoughts
• Composer can help create reusable packages
• Dependency Injection is a must,
• Yet be careful on how many dependencies are injected
• Testing has become easier
• Decoupling of modules is now easier
• Magento 2 service contracts / Design by contract ( Interfaces )
Thank-you and any questions ?