Slide 1

Slide 1 text

PRESENTED BY JOSHUA WARREN PRESENTED AT NORTHEAST PHP 2015 Magento 2 AN INTRODUCTION TO A MODERN PHP- BASED SYSTEM

Slide 2

Slide 2 text

MY EXPERIENCE

Slide 3

Slide 3 text

JoshuaWarren.com My Experience PHP Developer Since 1999 Founded Creatuity in 2008 Focused on the Magento platform Magento 2 contributor #NEPHP

Slide 4

Slide 4 text

JoshuaWarren.com early adopter of both Magento 1 and Magento 2 #NEPHP

Slide 5

Slide 5 text

JoshuaWarren.com Frequent Magento presenter #NEPHP

Slide 6

Slide 6 text

JoshuaWarren.com Active member of the #RealMagento community #NEPHP

Slide 7

Slide 7 text

JoshuaWarren.com Involved in feedback and design discussions throughout the Magento 2 Developer Beta #NEPHP

Slide 8

Slide 8 text

JoshuaWarren.com Wrote Writing the book on Magento 2 #NEPHP

Slide 9

Slide 9 text

A BRIEF HISTORY OF MAGENTO Photo courtesy of @YoavKutner

Slide 10

Slide 10 text

JoshuaWarren.com Magento 1 development began in 2007 by Varien, a PHP development agency. #NEPHP

Slide 11

Slide 11 text

JoshuaWarren.com In 2007, osCommerce was state of the art. #NEPHP

Slide 12

Slide 12 text

JoshuaWarren.com Cloud-based eCommerce systems didn’t exist. #NEPHP

Slide 13

Slide 13 text

JoshuaWarren.com PHP 5.2 was cutting-edge. #NEPHP

Slide 14

Slide 14 text

JoshuaWarren.com Composer didn’t exist, and Zend Framework 1 was still in early beta. #NEPHP

Slide 15

Slide 15 text

JoshuaWarren.com Magento 1 was built to resolve the pain points of osCommerce. #NEPHP

Slide 16

Slide 16 text

JoshuaWarren.com Designed to be more flexible and to provide standardized ways to customize the platform. #NEPHP

Slide 17

Slide 17 text

JoshuaWarren.com By 2010, Magento had been downloaded 1.5 million times. #NEPHP

Slide 18

Slide 18 text

JoshuaWarren.com Attracted by Magento’s free, open- source approach, hundreds of thousands of sites were launched using Magento 1. #NEPHP

Slide 19

Slide 19 text

JoshuaWarren.com There’s just one problem… #NEPHP

Slide 20

Slide 20 text

JoshuaWarren.com Ecommerce development is hard. #NEPHP

Slide 21

Slide 21 text

No content

Slide 22

Slide 22 text

JoshuaWarren.com Lightly documented ecommerce development is even harder. #NEPHP

Slide 23

Slide 23 text

No content

Slide 24

Slide 24 text

JoshuaWarren.com Varien, now known as Magento Inc, is acquired by eBay in 2011. #NEPHP

Slide 25

Slide 25 text

JoshuaWarren.com Work begins on Magento 2 almost immediately. #NEPHP

Slide 26

Slide 26 text

JoshuaWarren.com Now the most widely-used eCommerce platform, powering over 250,000 sites, expectations are high for the Magento 2 team. #NEPHP

Slide 27

Slide 27 text

JoshuaWarren.com Fewer than 30 commits are made to Magento 2 in 2012. #NEPHP

Slide 28

Slide 28 text

JoshuaWarren.com Internal priorities continue to shift, and finally at the end of 2014, Magento 2 development is made public on Github. #NEPHP

Slide 29

Slide 29 text

JoshuaWarren.com Magento commits to a release schedule for Magento 2, and announces the acceptance of pull requests. #NEPHP

Slide 30

Slide 30 text

JoshuaWarren.com devdocs.magento.com launches with significant documentation of Magento 2. #NEPHP

Slide 31

Slide 31 text

JoshuaWarren.com Developer Beta is released in December 2014; Merchant Beta in July 2015 #NEPHP

Slide 32

Slide 32 text

JoshuaWarren.com Production-ready release (‘general availability’) scheduled for Q4 2015 #NEPHP

Slide 33

Slide 33 text

MAGENTO 2 github.com/magento/magento2

Slide 34

Slide 34 text

JoshuaWarren.com Feature parity with Magento 1 + UI/UX Improvements + focus on resolving technical debt #NEPHP

Slide 35

Slide 35 text

JoshuaWarren.com Technologies #NEPHP

Slide 36

Slide 36 text

JoshuaWarren.com #NEPHP Composer composer create-project magento/product-community-edition --stability="beta"

Slide 37

Slide 37 text

JoshuaWarren.com Each Magento 2 module is a separate Composer package #NEPHP

Slide 38

Slide 38 text

JoshuaWarren.com PSR-0 thru PSR-4 #NEPHP

Slide 39

Slide 39 text

JoshuaWarren.com Testing built in from the start. phpunit, selenium, JMeter, Jasmine #NEPHP

Slide 40

Slide 40 text

JoshuaWarren.com magento2/dev/tests/ #NEPHP

Slide 41

Slide 41 text

JoshuaWarren.com HTML5, CSS3, LESS CSS Preprocessor, JQuery, RequireJS #NEPHP

Slide 42

Slide 42 text

JoshuaWarren.com Components from Zend Framework 1, Zend Framework 2, Symfony #NEPHP

Slide 43

Slide 43 text

JoshuaWarren.com Technical Architecture #NEPHP

Slide 44

Slide 44 text

JoshuaWarren.com Presentation Layer, Service Layer, Domain Layer, Persistence Layer #NEPHP

Slide 45

Slide 45 text

JoshuaWarren.com #NEPHP

Slide 46

Slide 46 text

JoshuaWarren.com Presentation Layer - views, literally and figuratively #NEPHP

Slide 47

Slide 47 text

JoshuaWarren.com Service Layer - an intermediary between the presentation and model layers #NEPHP

Slide 48

Slide 48 text

JoshuaWarren.com Service layer provides a stable, backwards-compatible interface and forms the foundation for dependency injection. #NEPHP

Slide 49

Slide 49 text

JoshuaWarren.com Domain layer - business logic, including models. Contains the implementation of service contracts. #NEPHP

Slide 50

Slide 50 text

JoshuaWarren.com Persistence Layer - resource models that perform CRUD operations on database tables. #NEPHP

Slide 51

Slide 51 text

JoshuaWarren.com Some models use a single table, others continue to use the Entity-Attribute-Value design pattern used in Magento 1. #NEPHP

Slide 52

Slide 52 text

JoshuaWarren.com Design Patterns #NEPHP

Slide 53

Slide 53 text

JoshuaWarren.com Loose Coupling #NEPHP

Slide 54

Slide 54 text

JoshuaWarren.com Dependency Injection #NEPHP

Slide 55

Slide 55 text

JoshuaWarren.com Service Contracts #NEPHP

Slide 56

Slide 56 text

JoshuaWarren.com Interceptors #NEPHP

Slide 57

Slide 57 text

JoshuaWarren.com Semantic Versioning #NEPHP

Slide 58

Slide 58 text

DEPENDENCY INJECTION Sorry - no cool photo here, because I don’t like needles…

Slide 59

Slide 59 text

JoshuaWarren.com DI is exactly what it sounds like - injecting dependencies into the objects that need them. #NEPHP

Slide 60

Slide 60 text

JoshuaWarren.com DI is designed to reduce dependencies and promote loose coupling #NEPHP

Slide 61

Slide 61 text

JoshuaWarren.com DI makes unit testing much easier #NEPHP

Slide 62

Slide 62 text

JoshuaWarren.com Magento 2 uses the Constructor Injection pattern of DI #NEPHP

Slide 63

Slide 63 text

JoshuaWarren.com DI in Magento 2 is handled via XML files #NEPHP

Slide 64

Slide 64 text

JoshuaWarren.com #NEPHP di.xml 
 
 
 Magento_SamplePaymentProvider::form/payinstore.phtml 
 
 
 


Slide 65

Slide 65 text

INTERCEPTORS

Slide 66

Slide 66 text

JoshuaWarren.com Plugin system based on the interceptor pattern #NEPHP

Slide 67

Slide 67 text

JoshuaWarren.com Calls to almost any module can be intercepted and altered #NEPHP

Slide 68

Slide 68 text

JoshuaWarren.com Vast improvement over the rewrite pattern in Magento 1 - no more rewrite conflicts #NEPHP

Slide 69

Slide 69 text

JoshuaWarren.com #NEPHP di.xml 
 
 
 


Slide 70

Slide 70 text

JoshuaWarren.com Sort order defines order if multiple plugins intercept the same item #NEPHP

Slide 71

Slide 71 text

JoshuaWarren.com Possible to intercept before, after and around a function #NEPHP

Slide 72

Slide 72 text

JoshuaWarren.com #NEPHP ‘Before’ Interceptor class Plugin
 {
 public function beforeSetName(\Magento\Catalog\Model\Product $subject, $name)
 {
 return array('(' . $name . ')');
 }
 }

Slide 73

Slide 73 text

JoshuaWarren.com #NEPHP ‘After’ Interceptor class Plugin
 {
 public function afterGetName(\Magento\Catalog\Model\Product $subject, $result)
 {
 return '|' . $result . '|';
 }
 }

Slide 74

Slide 74 text

JoshuaWarren.com #NEPHP ‘Around’ Interceptor class Plugin
 {
 public function aroundSave(\Magento\Catalog\Model\Product $subject, \Closure $proceed)
 {
 $this->doSomethingBeforeProductIsSaved();
 $returnValue = $proceed();
 if ($returnValue) {
 $this->postProductToFacebook();
 }
 return $returnValue;
 }
 }

Slide 75

Slide 75 text

SERVICE CONTRACTS Credit to Allan MacGregor for the Soylent Green joke.

Slide 76

Slide 76 text

JoshuaWarren.com Set of interfaces to define the public API of a module #NEPHP

Slide 77

Slide 77 text

JoshuaWarren.com This API is the interface provided to other modules to access its implementation #NEPHP

Slide 78

Slide 78 text

JoshuaWarren.com Designed to hide business logic behind a stable interface #NEPHP

Slide 79

Slide 79 text

JoshuaWarren.com Service contracts + semantic versioning = minor releases will not break existing code #NEPHP

Slide 80

Slide 80 text

JoshuaWarren.com @deprecated = will be removed with the next major version release #NEPHP

Slide 81

Slide 81 text

JoshuaWarren.com #NEPHP CustomerRepositoryInterface.php 
 namespace Magento\Customer\Api;
 /**
 * Customer CRUD interface.
 */
 interface CustomerRepositoryInterface
 {
 /**
 * Create customer.
 *
 * @api
 * @param \Magento\Customer\Api\Data\CustomerInterface $customer
 * @param string $passwordHash
 * @return \Magento\Customer\Api\Data\CustomerInterface
 * @throws \Magento\Framework\Exception\InputException If bad input is provided
 * @throws \Magento\Framework\Exception\State\InputMismatchException If the provided email is already used
 * @throws \Magento\Framework\Exception\LocalizedException
 */
 public function save(\Magento\Customer\Api\Data\CustomerInterface $customer, $passwordHash = null);

Slide 82

Slide 82 text

JoshuaWarren.com #NEPHP CustomerRepositoryInterface.php /**
 * Retrieve customer.
 *
 * @api
 * @param string $email
 * @param int|null $websiteId
 * @return \Magento\Customer\Api\Data\CustomerInterface
 * @throws \Magento\Framework\Exception\NoSuchEntityException If customer with the specified email does not exist.
 * @throws \Magento\Framework\Exception\LocalizedException
 */
 public function get($email, $websiteId = null);
 /**
 * Retrieve customer.
 *
 * @api
 * @param int $customerId
 * @return \Magento\Customer\Api\Data\CustomerInterface
 * @throws \Magento\Framework\Exception\NoSuchEntityException If customer with the specified ID does not exist.
 * @throws \Magento\Framework\Exception\LocalizedException
 */
 public function getById($customerId);


Slide 83

Slide 83 text

JoshuaWarren.com Service Contracts include Data Interfaces and Service Interfaces #NEPHP

Slide 84

Slide 84 text

JoshuaWarren.com Data Interfaces return information about data entities #NEPHP

Slide 85

Slide 85 text

JoshuaWarren.com Service Interfaces handle business logic #NEPHP

Slide 86

Slide 86 text

JoshuaWarren.com Three types of service interfaces in Magento 2 (so far) #NEPHP

Slide 87

Slide 87 text

JoshuaWarren.com Repository Interfaces provide access to persistent data entities #NEPHP

Slide 88

Slide 88 text

JoshuaWarren.com CustomerRepositoryInterface, AddressRepositoryInterface, etc. #NEPHP

Slide 89

Slide 89 text

JoshuaWarren.com Repository interfaces contain the CRUD operations #NEPHP

Slide 90

Slide 90 text

JoshuaWarren.com Management interfaces contain management functions not related to repositories #NEPHP

Slide 91

Slide 91 text

JoshuaWarren.com Validators, createAccount, changePassword, etc #NEPHP

Slide 92

Slide 92 text

JoshuaWarren.com Metadata interfaces provide meta information - primarily about custom attributes #NEPHP

Slide 93

Slide 93 text

EXTENDING MAGENTO 2

Slide 94

Slide 94 text

JoshuaWarren.com Create your basic module file structure #NEPHP

Slide 95

Slide 95 text

JoshuaWarren.com #NEPHP App/Code/// composer.json etc/module.xml Test/Unit/

Slide 96

Slide 96 text

JoshuaWarren.com #NEPHP Composer.json { "name": "joshuaswarren/sample-module-minimal", "description": "A minimal sample Magento 2 module", "type": "magento2-module", "version": "1.0.0", "license": [ "OSL-3.0", "AFL-3.0" ], "require": { "php": "~5.5.0|~5.6.0", "magento/magento-composer-installer": "*" }, "extra": { "map": [ [ "*", "joshuaswarren/SampleMinimal" ] ] } }

Slide 97

Slide 97 text

JoshuaWarren.com #NEPHP etc/module.xml

Slide 98

Slide 98 text

JoshuaWarren.com Optional config files in etc: acl.xml config.xml di.xml webapi.xml #NEPHP

Slide 99

Slide 99 text

JoshuaWarren.com acl.xml defines new items for Magento’s ACL system #NEPHP

Slide 100

Slide 100 text

JoshuaWarren.com Config.xml adds new configuration options #NEPHP

Slide 101

Slide 101 text

JoshuaWarren.com Webapi.xml defines items to expose via the REST or SOAP APIs #NEPHP

Slide 102

Slide 102 text

JoshuaWarren.com Optional subdirectories in etc: adminhtml frontend webapi_rest webapi_soap #NEPHP

Slide 103

Slide 103 text

JoshuaWarren.com Items in the main etc directory apply globally to your extension #NEPHP

Slide 104

Slide 104 text

JoshuaWarren.com Items in the 4 subdirectories apply only to that area - i.e., adminhtml only applies to the Magento backend #NEPHP

Slide 105

Slide 105 text

JoshuaWarren.com Optional subdirectories: API Block Controller Helper Model #NEPHP

Slide 106

Slide 106 text

JoshuaWarren.com Optional subdirectories: Plugin Setup Ui i18n view #NEPHP

Slide 107

Slide 107 text

JoshuaWarren.com API contains any new service contracts your extension adds #NEPHP

Slide 108

Slide 108 text

JoshuaWarren.com Block contains any new template blocks your extension adds #NEPHP

Slide 109

Slide 109 text

JoshuaWarren.com Controller contains your extension’s controllers #NEPHP

Slide 110

Slide 110 text

JoshuaWarren.com Helper contains any helper functions that your extension needs #NEPHP

Slide 111

Slide 111 text

JoshuaWarren.com Model contains your extension’s models #NEPHP

Slide 112

Slide 112 text

JoshuaWarren.com Plugin contains any interceptors your extension defines #NEPHP

Slide 113

Slide 113 text

JoshuaWarren.com Setup contains your database migrations using Magento’s setup script system #NEPHP

Slide 114

Slide 114 text

JoshuaWarren.com UI is for Magento 2’s new Magento UI library #NEPHP

Slide 115

Slide 115 text

JoshuaWarren.com I18n contains internationalization files - CSV files defining the translations for your strings #NEPHP

Slide 116

Slide 116 text

JoshuaWarren.com View contains the views for your extension #NEPHP

Slide 117

Slide 117 text

JoshuaWarren.com If your extension doesn’t need one of these items, just omit that folder #NEPHP

Slide 118

Slide 118 text

JoshuaWarren.com Sample: custom shipping method to allow for in-store pickup from several locations #NEPHP

Slide 119

Slide 119 text

JoshuaWarren.com #NEPHP Block/System/Config/Form/Field/Locations.php namespace Magento\SampleShippingProvider\Block\System\Config\Form\Field;
 use Magento\Config\Block\System\Config\Form\Field\FieldArray\AbstractFieldArray;
 /**
 * Backend system config array field renderer
 */
 class Locations extends AbstractFieldArray
 {
 /**
 * Initialise columns for 'Store Locations'
 *
 * @return void
 */
 protected function _construct()
 {
 $this->addColumn('title',
 ['label' => __('Title'), 'class' => 'validate-no-empty validate-alphanum-with-spaces']);
 $this->addColumn('street',
 ['label' => __('Street Address'), 'class' => 'validate-no-empty validate-alphanum-with-spaces']);
 $this->addColumn('phone',
 ['label' => __('Phone Number'), 'class' => 'validate-no-empty validate-no-empty validate-phoneStrict']);
 $this->addColumn('message',
 ['label' => __('Message'), 'class' => 'validate-no-empty']);
 $this->_addAfter = false;
 parent::_construct();
 }
 }

Slide 120

Slide 120 text

JoshuaWarren.com #NEPHP Model/Type/Plugin/Onepage.php [1/2] namespace Magento\SampleShippingProvider\Model\Type\Plugin;
 use Magento\Checkout\Model\Type\Onepage as CheckoutOnePage;
 use Magento\SampleShippingProvider\Model\Carrier;
 /**
 * Change Shipping Address to selected Store location address
 */
 class Onepage
 {
 /**
 * @var Carrier
 */
 private $carrier;
 /**
 * @param Carrier $carrier
 */
 public function __construct(Carrier $carrier)
 {
 $this->carrier = $carrier;
 }


Slide 121

Slide 121 text

JoshuaWarren.com #NEPHP Model/Type/Plugin/Onepage.php [2/2] /**
 * Replace shipping address with pickup location address
 * @param CheckoutOnePage $subject
 * @param array $result
 * @return $this
 */
 public function afterSaveShippingMethod(CheckoutOnePage $subject, array $result)
 {
 if ($result) {
 return $result;
 }
 $quote = $subject->getQuote();
 $shippingAddress = $quote->getShippingAddress();
 $shippingMethod = $shippingAddress->getShippingMethod();
 /**
 * In-Store pickup selected
 * Update Shipping Address
 */
 if (strpos($shippingMethod, $this->carrier->getCarrierCode()) !== false) {
 $locationAddress = $this->carrier->getLocationInfo($shippingMethod);
 $shippingAddress->setCountryId($locationAddress['country_id']);
 $shippingAddress->setRegionId($locationAddress['region_id']);
 $shippingAddress->setPostcode($locationAddress['postcode']);
 $shippingAddress->setCity($locationAddress['city']);
 $shippingAddress->setStreet($locationAddress['street']);
 $shippingAddress->setTelephone($locationAddress['phone']);
 }
 return $result;
 }
 }

Slide 122

Slide 122 text

JoshuaWarren.com #NEPHP Model/Carrier.php namespace Magento\SampleShippingProvider\Model;
 use Psr\Log\LoggerInterface;
 use Magento\Framework\App\Config\ScopeConfigInterface;
 use Magento\Store\Model\ScopeInterface;
 use Magento\Shipping\Model\Carrier\AbstractCarrier;
 use Magento\Shipping\Model\Carrier\CarrierInterface;
 use Magento\Shipping\Model\Config;
 use Magento\Shipping\Model\Rate\ResultFactory;
 use Magento\Quote\Model\Quote\Address\RateResult\MethodFactory;
 use Magento\Quote\Model\Quote\Address\RateResult\ErrorFactory;
 /**
 * In-Store Pickup shipping model
 */
 class Carrier extends AbstractCarrier implements CarrierInterface
 {
 /**
 * @var string
 */
 protected $_code = 'storepickup';
 /**
 * @var bool
 */
 protected $_isFixed = true; … see https://github.com/magento/magento2-samples/blob/master/sample-module-shipping-provider/Model/Carrier.php 


Slide 123

Slide 123 text

JoshuaWarren.com In model/carrier.php we implement all of the functions a shipping carrier must have in Magento 2 #NEPHP

Slide 124

Slide 124 text

JoshuaWarren.com GetAllowedMethods CollectRates GetLocationInfo BuildRateForLocation GetLocations GetShippingOrigin #NEPHP

Slide 125

Slide 125 text

JoshuaWarren.com #NEPHP Etc/Adminhtml/System.xml 
 
 
 In-Store Pickup
 
 Enabled
 Magento\Config\Model\Config\Source\Yesno
 
 Warning: Shipping Origin should be configured to use this method.]]>
 
 
 
 Title
 
 […]

Slide 126

Slide 126 text

JoshuaWarren.com #NEPHP Etc/Frontend/di.xml 
 
 
 
 


Slide 127

Slide 127 text

JoshuaWarren.com #NEPHP Etc/Config.xml 
 
 
 
 1
 Magento\SampleShippingProvider\Model\Carrier
 In-Store Pickup
 This shipping method is not available.
 
 
 


Slide 128

Slide 128 text

JoshuaWarren.com #NEPHP Etc/Module.xml 
 
 


Slide 129

Slide 129 text

JoshuaWarren.com #NEPHP Composer.json { "name": "magento/sample-module-shipping-provider", "description": "Demonstrate Shipping Provider", "type": "magento2-module", "version": "1.0.0", "license": [ "OSL-3.0", "AFL-3.0" ], "require": { "php": "~5.5.0|~5.6.0", "magento/magento-composer-installer": "*", "magento/framework": "~0.74", "magento/module-store": "~0.74", "magento/module-shipping": "~0.74", "magento/module-quote": "~0.74", "magento/module-checkout": "~0.74" }, "extra": { "map": [ [ "*", "Magento/SampleShippingProvider" ] ] } }

Slide 130

Slide 130 text

JoshuaWarren.com We now have a complete, functioning in-store-pickup shipping extension for Magento 2 #NEPHP

Slide 131

Slide 131 text

JoshuaWarren.com Take a look at the Test/Unit directory on Github for tests for this extension #NEPHP

Slide 132

Slide 132 text

JoshuaWarren.com Magento 2 unit testing includes mocking, fixtures, etc. - everything you need for TDD #NEPHP

Slide 133

Slide 133 text

LEARNING MORE Don’t end up like this guy ->

Slide 134

Slide 134 text

JoshuaWarren.com devdocs.magento.com magento.stackexchange.com/questions/tagged/magento2 #NEPHP

Slide 135

Slide 135 text

JoshuaWarren.com AlanStorm.com AlanKent.me CoderOnCode.com #NEPHP

Slide 136

Slide 136 text

JoshuaWarren.com Upcoming events: Meet Magento New York, ZendCon, php[world] #NEPHP

Slide 137

Slide 137 text

JoshuaWarren.com Programming With Magento 2 coming to amazon.com & phparch.com #NEPHP

Slide 138

Slide 138 text

Keep in Touch! joind.in/14737 @JoshuaSWarren JoshuaWarren.com Mage2DevBook.com

Slide 139

Slide 139 text

JoshuaWarren.com #NEPHP