分类
安装使用

在WSL2中使用 Docker搭建 Magento2.4x 的 LNMP本地开发环境(简单模式)

Magento2硬件环境门槛比之前Magento1高出很多,所以很多新手入门学习Magento2时,光搭建环境就用非常多的时间,特别很多新人还是习惯使用windows 来搭建自己的本地开发环境。 在此,我分享一个比较快速的使用 Docker 搭建 Magento2的LNMP本地开发环境介绍。

本人初次使用Docker 来部署本地开发环境,所以用了很多研究时间熟悉环境上的部署,最后发现可以简单使用现有的别人已封装好的Image(Docker镜像)来部署本地。 所以本贴我暂时定义为一个简单模式安装Magento2本地开发环境来介绍,方便新手更快的上手,至于后期能纯DIY搭建Docker为Magento2用时,我会再单独另外分享一个完整版DIY版。

本地环境硬件配置如下:

CPU AMD R7 5700U  8核16线程

内存 16G DDR4 3200

硬盘  西部数据 SSD硬盘

操作系统: Windows 11 家庭版 (21H2)

虚拟环境及工具: WSL2 + Debian + Docker Desktop + VS code

虚拟环境安装可以参考底部文章链接进行安装。或者参考本论坛文章的安装子系统和WSL2安装部分(可以用ubuntu也可以用debian,看个人偏好)

我是直接在 powershell 里

wsl install -d

一路装过来的,特别注意就是一般W10以上都需要下载最新的Linux内核组件,否则WSL2装不上。 另外我并没有使用推荐的W自带的 Hyper-V 组件,因为看介绍其限制了一些功能使用, 于是我纯装了 WSL2, 然后开 docker desktop 就可以在 debian命令窗口里直接执行 docker 相关所有命令。 我个人归纳初步对docker的理解就是一台可以自定义的本地虚拟服务器,里面可以配置你想要的任何软件和环境,所有当前市面已知的通用服务和工具,都在 hub.docker.com 下有官方镜像(image)可下载,  而你的任务就是把这些镜像组装到一个容器里实现你本地开发环境需求。对容器需要深入理解的可以查看其他的文献补充知识点,我也是仅学到点皮毛。

当你看到docker run hello-world执行成功后, 表示docker 已成功安装完毕。在 Debian 命令行窗口执行以下命令:

docker run -d --net=bridge -v /var/lib/mysql -v /home/cloudpanel --restart=always --privileged -h mgt-dev --name mgt-dev -it -p 80:80 -p 443:443 -p 8443:8443 -p 22:22 -p 3306:3306 -p 9200:9200 -p 15672:15672 mgtcommerce/mgt-dev:v2

执行成功后,会出现一个 mgt-dev 的容器,这个就是magento2的开发环境一键包 mgtcommerce/mgt-dev:v2 镜像,使用这个一键包的镜像大约需要2-5G空间,安装时自动会下载。 该镜像要使用Https 来访问本地网页,需要游览器强制通过安全验证打开,这个也有利于后期的开发, 毕竟现在绝大部分B端都是HTTPS了,纯HTTP的开发基本没有了。

这个镜像自带了很多功能,我来简单介绍下安装时需要用到的一些内容:

  • https://127.0.0.1:8443  这是一个它自己的虚拟空间管理器,用这个工具可以做以下这些事:
  • 创建虚拟域名 (包含根目录路径配置)
  • Vhost 的配置
  • PHP环境参数设置
  • 查看 ngnix (access/error) log / php error log
  • 创建数据库+一键打开 phpMyAdmin + 上传下载数据库
  • SSH控制URSER权限管理
  • CronJob 管理器
  • 包含的服务有(非全部):
  • Nginx
  • PHP-FPM
  • Varnish
  • Mysql
  • Elasticserach
  • Cron
  • Supervisord
  • rabbitMq
  • Redis

该镜像启动后会占用大约3-6G左右虚拟空间(即你的物理内存),现在需要用 VSCODE链接到该容器(提醒:是连接到容器而不是连接虚拟机),它根目录是

/home/cloudpanel/htdocs/ 

你代码开发是在这个路径下的(如果你的 vscode没有安装 Remote – Containers 插件,请安装后重启vscode就可以在远程容器下拉菜单里找到 mgt-dev 容器)。

现在开始安装Magento2,我并没有按文献解说用composer安装,我直接从官网下载了 2.4.3-p1包的 tar.gz版本,然后直接通过vscode窗口丢进去,它会自动上传到容器里,然后解压手工安装的。 上传完毕后,你需要进入mgt-dev 容器操作相关命令,具体步骤如下:

  • 我本地Docker安装了 portainer 容器管理器(需要的可以自行安装),非常方便可视化管理你的容器和镜像,直接点容器列表的命令行按钮, 就可以进入 mgt-dev 容器命令行模式;

没有管理工具的, 需要在 debian窗口执行:

docker exec -it mgt-dev /bin/bash
  • 进入mgt-dev 容器命令窗口后,打开目录 cd /home/cloudpanel/htdocs/ ,所有开发代码都是在这个目录下的;
  • 创建一个新文件夹,例如 magento2.mgt , 用 mkdir magento2.mgt 或者 vscode创建新文件夹都可以;
  • 然后通过vscode 把刚才说下载好的 xxxx.tar.gz源码包丢进去这个新目录里;
  • 上传完毕后, 在容器里执行:
cd /home/cloudpanel/htdocs/magento2.mgt 
tar -zxvf xxxx.tar.gz

(XXXX.tar.gz 就是你的MAGENTO源码包)

根目录包位置为  

/home/cloudpanel/htdocs/magento2.mgt /pub

(填写只需要写 magento2.mgt/pub) 

Vhost 选择 Magento2 (可以看到他还有普通模式,以后用于非magento软件开发也不错的)

Php 的版本选 7.4

  • 创建新的数据库,定义为

Dbname:  magento2

User: magento2

Password: magento2

  • 回到mgt-dev容器命令行窗口,确保当前目录位置为 /home/cloudpanel/htdocs/magento2.mgt 后,执行以下命令:
bin/magento setup:install --backend-frontname='admin' 
--session-save='files' 
--db-host='127.0.0.1' 
--db-name='magento2' --db-user='magento2' 
--db-password='magento2' --base-url='https://magento2.mgt/' 
--base-url-secure='https://magento2.mgt/' 
--admin-user='admin' --admin-password='admin123' 
--admin-email='john@doe.com' 
--admin-firstname='John' --admin-lastname='Doe'

这个安装需要一点时间,如果带有DEMO数据,那会比较长。安装完毕后执行

bin/magento module:disable Magento_TwoFactorAuth
chmod -R 777 /home/cloudpanel/htdocs/magento2.mgt/

因为纯本地开发环境,全部777问题不大。

10. 修改hosts 文件(C:\Windows\System32\Drivers\etc\hosts),增加

127.0.0.1 magento2.mgt

如果无法直接修改成功(类似被其他程序占用啥啥的)直接以管理员身份执行powershell, 然后执行:

notepad C:\Windows\System32\Drivers\etc\hosts

这可以强制修改成功 (我本地装了VIM去编辑的,有兴趣自己去摸索下)

打开前台地址 https://magento2.mgt/

打开后台地址 https://magento2.mgt/admin/  (后台账号密码为 admin / admin123)

这样你本地magento2开发环境就初步架设完毕了。据测试,deploy一次大约11秒,性能上来说,感觉wsl2优化了一部分IO瓶颈的读写问题,但是非常吃内存,当我全部打开相关软件开始编辑时,内存已经吃到 12G (本身可用内存只有 13.8G,需要留2G多给核显),内存90%以上,所以接下来我首要工作,是得换个大点的内存条了 T_T

参考文献:

Windows下安装Docker

https://www.runoob.com/docker/windows-docker-install.html

用于M2封包Docker本地开发环境安装

https://www.mgt-commerce.com/tutorial/setup-magento-2-local-development-environment-with-docker/

分类
安装使用

Magento2 本地环境出现 502 bad gateway 的修正方法

Magento2本地安装遇到502 bad gateway的错误,大概率是因为nginx 的配置限制的问题。出现502 bad gateway时,可以通过 nginx 的日志发现错误的原因倾向。 由于Magento2 的页面输出时,Http 头会携带很多验证类相关的信息,而由于本地环境限制很大,大部分集成环境容易出现信息丢包,所以需要修改nginx 的配置文件来加大http头的载入。需要修改 nginx.conf 文件,在 http{} 的声明区域添加:

fastcgi_buffers 16 16k;
fastcgi_buffer_size 32k;
proxy_buffer_size 128k;
proxy_buffers 4 256k;
proxy_busy_buffers_size 256k;

然后再重启nginx,就有可能修复 502 bad gateway 的问题。祝君好运。

分类
安装使用

Magento2.4.1 后台分类编辑里显示前台对应分类商品展示总数方法

在后台分类编辑里,左侧的分类树中,每个分类ID后面的商品总数始终是该分类下所有商品的总数,和前台已展示的商品总数不一致。通过深入挖掘,发现一个核心文件的代码存在低级逻辑错误,怀疑是开源版本的一个被阉割后的人工BUG。原文件为

\vendor\magento\module-catalog\Model\ResourceModel\Category\Collection.php

先翻看到以下方法的位置:

public function loadProductCount($items, $countRegular = true, $countAnchor = true)

{

……
        if ($countAnchor) {
            // Retrieve Anchor categories product counts
            $categoryIds = array_keys($anchor);
            $countSelect = $this->getProductsCountQuery($categoryIds, (bool)$websiteId);
            $categoryProductsCount = $this->_conn->fetchPairs($countSelect);
            foreach ($anchor as $item) {
                $productsCount = isset($categoriesProductsCount[$item->getId()])
                    ? (int)$categoryProductsCount[$item->getId()]
                    : $this->getProductsCountFromCategoryTable($item, $websiteId);
                $item->setProductCount($productsCount);
            }
……
}
 
其中 $categoriesProductsCount 这个变量是错误的,前后文响应看应该是变量 $categoryProductsCount 才能前后匹配 。这处修改好后,我们再来到以下方法的位置:
 
private function getProductsCountQuery(array $categoryIds, $addVisibilityFilter = true): Select
{
       $categoryTable = $this->getTable(‘catalog_category_product_index’);
……
 
这个表名 catalog_category_product_index 也是不正确的,因为这个表名是默认STORE ID=0 的表,正常情况下这个表里不会有数据的, 所有分类商品索引只有在STORE级别才有数据,我们可以修改为:
 
        $tableName = ‘catalog_category_product_index’;
        $storeId = $this->getProductStoreId();
        if (!empty($storeId)){
            $tableName .= ‘_store’.$storeId;
        }
        $categoryTable = $this->getTable($tableName);
     
具体应用的时候,可以查看自己数据库里分类商品索引对应的表名是否匹配。 在修改过这两处后,后台效果如下:

以上图示的效果,默认全局店铺下会显示分类下所有商品总数,而选择好店铺后,仅显示可展示的总数,对于有需要如此修改的需求,可以考虑复写这个核心文件,改动上文提到的两处对应代码即可。

分类
安装使用

Magento 2 + Elasticsearch 产品列表排序修改

本文来自社区成员 土豆 的投稿

在Magento2.4.x 版本之前也有人介绍过商品列表默认产品排序为新产品在前面的方法,但是在Magento2.4.X 强制使用Elasticserach后就不生效了。

例如:

https://forum.magentochina.org/t/magento2%E5%A6%82%E4%BD%95%E4%BF%AE%E6%94%B9%E9%BB%98%E8%AE%A4%E7%9A%84%E4%BA%A7%E5%93%81%E6%8E%92%E5%BA%8F%E6%96%B9%E5%BC%8F/130

if ($this->getCurrentOrder()) {
     if(($this->getCurrentOrder())=='position'){
             $this->_collection->setOrder('entity_id','desc');
     }
     else {
             $this->_collection->setOrder($this->getCurrentOrder(),$this->getCurrentDirection());
     }
 }

但是在 Magento2.4 开始强制使用 elasticsearch (简称ES) 后,以上方法已经不能生效。简单的说是因为FULLTEXT全文索引的缘故。由于使用了ES 后, 列表的相关商品数据都会通过索引进入ES 缓存里, 而使用类似 entity_id desc 这样的无法生效,因为 entity_id 并没有进入到ES 缓存数据的字段中。通过观察, Magento2.4.x 的 ES 里缓存的数据都是由属性为单位进入到ES 缓存中, 但是商品的 created_at 字段未进入到ES。 我在这里介绍只需要2个步骤,就可以让 created_at 属性进入到ES并作用于商品列表页默认叠加排序 (也包括搜索页)。

首先, 商品 created_at 属性在后台商品属性编辑里都无法查询到(因为它是Magento2里的隐藏属性),可以通过直接修改数据库或者更新脚本等方法, 更新以下SQL:

UPDATE catalog_eav_attribute AS cea
     INNER JOIN eav_attribute AS ea
         ON ea.attribute_id = cea.attribute_id AND ea.entity_type_id = 4
 SET cea.used_in_product_listing = 1, cea.used_for_sort_by = 1
 WHERE ea.attribute_code IN ('created_at');

以上更新会让 created_at 属性进入到商品列表字段和SORT BY的应用, 然后执行

php bin/magento index:reindex

刷新索引,等刷新完毕后, 再次查看ES 的商品缓存数据就包含了 created_at 数据。第一步完成。

然后,需要修改商品列表的 Toolbar 类, 原生文件是:

vendor/magento/module-catalog/Block/Product/ProductList/Toolbar.php

我们需要利用plugin修改它其中2个方法。 先在你已有的自定义模块 etc/di.xml 文件中添加以下代码:

<type name="Magento\Catalog\Block\Product\ProductList\Toolbar">
	<plugin name="yourpackage_yourmodel_block_productlist_toolbar"
		type="Yourpackage\Yourmodel\Plugin\Block\Product\ProductList\Toolbar"
		sortOrder="10000" />
</type>

其中 sortOrder 设置为10000的缘故是让这条修改权重尽可能的最后执行, 考虑到可能其他某些插件会优先执行其他算法。然后添加

Yourpackage\Yourmodel\Plugin\Block\Product\ProductList\Toolbar.php

该文件代码如下:

<?php
namespace Yourpackage\Yourmodel\Plugin\Block\Product\ProductList;

use Magento\Catalog\Block\Product\ProductList\Toolbar as VendorProductToolbar;

class Toolbar extends VendorProductToolbar
{ public function afterSetCollection( VendorProductToolbar $toolbar, $result) { $collection = $result->getCollection(); if (!$collection->isLoaded()){ $collection->setOrder('created_at','DESC'); $result->_collection = $collection; } return $result; } public function afterGetAvailableOrders(VendorProductToolbar $toolbar, $result) { if(array_key_exists('created_at', $result)){ unset($result['created_at']); } return $result; } }

其中 afterSetCollection 是最终增加 created_at 属性的 SORT 排序, 在使用ES的情况下, 每个应用于 SORT的属性字段都要事先单独插入到ES缓存中(就是第一步所作的内容),并设置 used_for_sort_by 为真,否则无法自动查询到匹配的排序字段。正是因为我们设置了 used_for_sort_by 为真,在商品列表 sort by 下拉窗口默认就会展示出来created_at,所以我们需要用 afterGetAvailableOrders 方法去隐藏该选项。

完成以上操作后,刷新缓存后就可以看到效果了。