模块的路径是这样的,开发商名称和模块名称都使用 大驼峰 的形式命名
app/code/开发商名称/模块名称
默认路由是这样的
routeid/controller/action
app/code/LocalDev/HelloModule
<?php
\Magento\Framework\Component\ComponentRegistrar::register(
\Magento\Framework\Component\ComponentRegistrar::MODULE,
'LocalDev_HelloModule',
__DIR__
);
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
<module name="LocalDev_HelloModule" setup_version="1.0.9"></module>
</config>
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/routes.xsd">
<router id="standard">
<route id="local_dev" frontName="local_dev">
<module name="LocalDev_HelloModule" />
</route>
</router>
</config>
Hello
World.php
<?php
namespace LocalDev\HelloModule\Controller\Hello;
class World extends \Magento\Framework\App\Action\Action
{
public function __construct(
\Magento\Framework\App\Action\Context $context)
{
return parent::__construct($context);
}
public function execute()
{
echo 'Hello World';
exit;
}
}
完整的模块目录结构是这样的
app
code
LocalDev
HelloModule
Controller
Hello
World.php
etc
frontend
routes.xml
module.xml
registration.php
启用模块和刷新缓存后,访问这样的链接 http://localhost-magento/local_dev/hello/world
,应该就能看到 hello world
的输出
<?xml version="1.0"?>
<schema xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/schema.xsd">
<table name="test_model" resource="default" engine="innodb" comment="Test Model">
<column xsi:type="int" name="entity_id" nullable="false" identity="true"/>
<column xsi:type="int" name="customer_id" nullable="false" comment="customer_id"/>
<column xsi:type="varchar" name="type" nullable="false" length="64" comment="type"/>
<constraint xsi:type="primary" referenceId="PRIMARY">
<column name="entity_id"/>
</constraint>
</table>
</schema>
<?php
namespace Vendor\Extension\Model\ResourceModel;
use Magento\Framework\Model\ResourceModel\Db\AbstractDb;
class TestModel extends AbstractDb
{
const TABLE_NAME = 'test_model';
protected function _construct()
{
$this->_init(self::TABLE_NAME, 'entity_id');
}
}
<?php
namespace Vendor\Extension\Model;
use Magento\Framework\Model\AbstractModel;
class TestModel extends AbstractModel
{
protected function _construct()
{
$this->_init(Vendor\Extension\Model\ResourceModel\TestModel::class);
}
}
<?php
namespace Vendor\Extension\Model\ResourceModel\TestModel;
use Magento\Framework\Model\ResourceModel\Db\Collection\AbstractCollection;
class Collection extends AbstractCollection
{
protected function _construct()
{
$this->_init(Vendor\Extension\Model\TestModel::class, Vendor\Extension\Model\ResourceModel\TestModel::class);
}
}
php bin/magento setup:db-declaration:generate-whitelist --module-name=Extension
php bin/magento setup:upgrade
<type name="Magento\Framework\Console\CommandList">
<arguments>
<argument name="commands" xsi:type="array">
<item name="exampleSayHello" xsi:type="object">Vendor\Extension\Console\SayHello</item>
</argument>
</arguments>
</type>
<?php
namespace Vendor\Extension\Console;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Input\InputOption;
class SayHello extends Command
{
const NAME = "name";
protected function configure()
{
$options = [
new InputOption(self::NAME, null, InputOption::VALUE_REQUIRED, 'a description text')
];
$this->setName("example:sayhello") // 命令的名字
->setDescription('example description') // 命令的描述
->setDefinition($options);
parent::configure();
}
protected function execute(InputInterface $input, OutputInterface $output)
{
if ($name = $input->getOption(self::NAME)) {
$output->writeln('hello ' . $name);
} else {
$output->writeln('hello world');
}
}
}
php bin/magento example:sayhello
php bin/magento setup:upgrade
更新数据php bin/magento list
,看看能不能找到新加的命令php bin/magento example:sayhello
参考 https://devdocs.magento.com/guides/v2.4/extension-dev-guide/cli-cmds/cli-howto.html
type Query
{
CustomGraphql (
username: String @doc(description: "Email Address/Mobile Number")
password: String @doc(description: "Password")
websiteId: Int = 1 @doc (description: "Website Id")
): CustomGraphqlOutput @resolver(class: "Vendor\\Extension\\Model\\Resolver\\CustomGraphql") @doc(description:"Custom Module Datapassing")
}
type CustomGraphqlOutput
{
customer_id: Int
type: String
type_id: Int
}
在模块目录 Model 下新建一个文件夹 Resolver ,然后再在这个文件夹里新建一个类文件 CustomGraphql.php 并写入以下内容
<?php
namespace Vendor\Extension\Model\Resolver;
use Magento\Framework\GraphQl\Config\Element\Field;
use Magento\Framework\GraphQl\Exception\GraphQlInputException;
use Magento\Framework\GraphQl\Query\ResolverInterface;
use Magento\Framework\GraphQl\Schema\Type\ResolveInfo;
class CustomGraphql implements ResolverInterface
{
/**
* @param Field $field
* @param \Magento\Framework\GraphQl\Query\Resolver\ContextInterface $context
* @param ResolveInfo $info
* @param array|null $value
* @param array|null $args
* @return array|\Magento\Framework\GraphQl\Query\Resolver\Value|mixed
* @throws GraphQlInputException
*/
public function resolve(
Field $field,
$context,
ResolveInfo $info,
array $value = null,
array $args = null)
{
if (!isset($args['username']) || !isset($args['password']) || !isset($args['websiteId'])||
empty($args['username']) || empty($args['password']) || empty($args['websiteId']))
{
throw new GraphQlInputException(__('Invalid parameter list.'));
}
$output = [];
$output['customer_id'] = 1;
$output['type'] = 'type';
$output['type_id'] = 1;
return $output ;
}
}
运行这句命令 php bin/magento setup:upgrade
更新数据
curl 'http://localhost-magento/graphql' \
-H 'accept: application/json' \
-H 'content-type: application/json' \
--data-raw '{"query":"\n query {\n CustomGraphql (\n customer_id: 123\n type: \"asd\"\n type_id: 321\n ) {\n customer_id\n type\n type_id\n }\n}","variables":{},"operationName":null}' \
--compressed \
--insecure -s -k
{
"data": {
"CustomGraphqlOutput": {
"customer_id": 123,
"type": "asd",
"type_id": 321,
"end_date": 456
}
}
}
curl 'https://localhost-magento/graphql' \
-H 'accept: application/json' \
-H 'content-type: application/json' \
--data-raw '{"query":"\n query IntrospectionQuery {\n __schema {\n \n queryType { name }\n mutationType { name }\n subscriptionType { name }\n types {\n ...FullType\n }\n directives {\n name\n description\n \n locations\n args {\n ...InputValue\n }\n }\n }\n }\n\n fragment FullType on __Type {\n kind\n name\n description\n \n fields(includeDeprecated: true) {\n name\n description\n args {\n ...InputValue\n }\n type {\n ...TypeRef\n }\n isDeprecated\n deprecationReason\n }\n inputFields {\n ...InputValue\n }\n interfaces {\n ...TypeRef\n }\n enumValues(includeDeprecated: true) {\n name\n description\n isDeprecated\n deprecationReason\n }\n possibleTypes {\n ...TypeRef\n }\n }\n\n fragment InputValue on __InputValue {\n name\n description\n type { ...TypeRef }\n defaultValue\n \n \n }\n\n fragment TypeRef on __Type {\n kind\n name\n ofType {\n kind\n name\n ofType {\n kind\n name\n ofType {\n kind\n name\n ofType {\n kind\n name\n ofType {\n kind\n name\n ofType {\n kind\n name\n ofType {\n kind\n name\n }\n }\n }\n }\n }\n }\n }\n }\n ","variables":{},"operationName":"IntrospectionQuery"}' \
--compressed -s -k
浏览器可以安装这个拓展 https://github.com/altair-graphql/altair
这是 graphql 的中文文档 https://graphql.cn/
参考 https://devdocs.magento.com/guides/v2.4/graphql/index.html
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Indexer/etc/indexer.xsd">
<indexer id="test_indexer"
view_id="test_indexer"
class="Vendor\Extension\Model\Indexer\Test"
>
<title translate="true">test_indexer</title>
<description translate="true">Test Indexer</description>
</indexer>
</config>
<?xml version="1.0" encoding="UTF-8"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:framework:Mview/etc/mview.xsd">
<view id="test_indexer"
class="Vendor\Extension\Model\Indexer\Test"
group="indexer" >
<subscriptions>
<table name="sales_order" entity_column="entity_id"/>
</subscriptions>
</view>
</config>
<?php
namespace Vendor\Extension\Model\Indexer;
class Test implements \Magento\Framework\Indexer\ActionInterface, \Magento\Framework\Mview\ActionInterface
{
/**
* @inheritdoc
*/
public function executeFull()
{
$this->reindex();
}
/**
* @inheritdoc
*/
public function executeList(array $ids)
{
$this->execute($ids);
}
/**
* @inheritdoc
*/
public function executeRow($id)
{
$this->execute([$id]);
}
/**
* @inheritdoc
*/
public function execute($ids)
{
$this->reindex($ids);
}
/**
* @param int[] $ids
* @return void
*/
protected function reindex($ids = null)
{
if ($ids === null) { // 更新全部索引
} else { // 根据传入的 id 更新索引
}
}
}
php bin/magento indexer:reindex test_indexer
后台 -> SYSTEM -> Index Management
php bin/magento indexer:reindex
php bin/magento indexer:reindex [indexer]
php bin/magento indexer:info
php bin/magento indexer:status
php bin/magento indexer:status [indexer]
php bin/magento indexer:show-mode
php bin/magento indexer:show-mode [indexer]
php bin/magento indexer:set-mode {realtime|schedule} [indexer]
php bin/magento indexer:reset
php bin/magento indexer:reset [indexer]
https://devdocs.magento.com/guides/v2.4/extension-dev-guide/indexing-custom.html
http://aqrun.oicnp.com/2019/11/10/12.magento2-indexing-reindex.html
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Cron:etc/crontab.xsd">
<group id="default">
<job name="order_complete_fulfillment_end_date_expire" instance="HKT\PartnerCode\Cron\Order\FulfillmentEndDateExpireCron" method="execute">
<schedule>0 2 * * *</schedule>
</job>
</group>
</config>
在模块目录 etc 新建 cron_groups.xml
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Cron:etc/cron_groups.xsd">
<group id="token_expired">
<schedule_generate_every>1</schedule_generate_every>
<schedule_ahead_for>4</schedule_ahead_for>
<schedule_lifetime>15</schedule_lifetime>
<history_cleanup_every>1440</history_cleanup_every>
<history_success_lifetime>60</history_success_lifetime>
<history_failure_lifetime>600</history_failure_lifetime>
<use_separate_process>1</use_separate_process>
</group>
</config>
group 节点的 id 对应 crontab.xml 里 config group 的 id
修改过 cron 和 cron_groups 需要重新编译并清空缓存才会生效
php bin/magento setup:di:compile
php bin/magento cache:clean
运行全部任务组
php bin/magento cron:run
运行 default 任务组,一般的定时任务都在 default
php bin/magento cron:run --group=default
运行 index 任务组,这是索引器的任务组,就是 by schedule 类型的索引器
php bin/magento cron:run --group=index
运行其他任务组修改 –group 参数就可以了
然后让 cron:run 一直运行就可以的了,官方文档提供了使用 crontab 的例子,默认情况下队列好像也是用 crontab 运行。
* * * * * php bin/magento cron:run
magneto 还提供了自动生成 crontab 配置的命令
php bin/magento cron:install # 加上 magento 的 cron ,不影响其他配置
php bin/magento cron:install --force # 加上 magento 的 cron ,清除其他配置
php bin/magento cron:remove # 移除 magento 的 cron
运行了 cron:install 后,可以用 crontab -l 来查看
crontab -l
#~ MAGENTO START c5f9e5ed71cceaabc4d4fd9b3e827a2b
* * * * * /usr/bin/php /var/www/html/magento2/bin/magento cron:run 2>&1 | grep -v "Ran jobs by schedule" >> /var/www/html/magento2/var/log/magento.cron.log
#~ MAGENTO END c5f9e5ed71cceaabc4d4fd9b3e827a2b
这是 crontab 配置的解释
自己写 crontab 配置或用其它方式(例如 supervisor )让 cron:run 一直运行也是可以的
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Event/etc/events.xsd">
<event name="customer_save_after_data_object">
<observer name="upgrade_order_customer_email" instance="Magento\Customer\Observer\UpgradeOrderCustomerEmailObserver"/>
<observer name="upgrade_quote_customer_email" instance="Magento\Customer\Observer\UpgradeQuoteCustomerEmailObserver"/>
</event>
</config>
Magento\Framework\Event\ObserverInterface
// 第一个参数是事件名;第二个参数是一个数组,用于传递参数给观察者
// $this->_eventManager 的类型 \Magento\Framework\Event\ManagerInterface
$this->_eventManager->dispatch(
'admin_user_authenticate_after',
['username' => $username, 'password' => $password, 'user' => $this, 'result' => $result]
);
在模块的 etc 文件夹下的 logging.xml 里加上类似这样的一段
<group name="order_retrievepayment">
<label translate="true">Order Retrieve Payment</label>
<expected_models>
<expected_model class="Magento\Sales\Model\Order"></expected_model>
</expected_models>
<events>
<event controller_action="adminportal_order_retrievepayment" action_alias="save" />
</events>
</group>
如果是 post 请求,那么需要在 event 节点里再加一个属性 post_dispatch=”postDispatchSimpleSave”
<event controller_action="adminportal_order_retrievepayment" action_alias="save" post_dispatch="postDispatchSimpleSave"/>
controller_action 是 模块名_控制器名_方法名 可以在这两个位置加断点,然后再运行一次请求,就知道具体的 controller_action 是什么了
vendor\magento\module-logging\Observer\ControllerPostdispatchObserver.php:52
vendor\magento\module-logging\Model\Processor.php:363
然后在后台里勾选对应的选项,按着这样的路径寻找
Stores
Settings
Configuration
Advanced
Admin
Admin Actions Logging
在配置文件里的 label
可以在后台里的这个位置查看日志
system -> action logs -> report
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Acl/etc/acl.xsd">
<acl>
<resources>
<resource id="Magento_Backend::admin">
<resource id="Magento_Sales::sales">
<resource id="Magento_Sales::sales_operation">
<resource id="Magento_Sales::sales_order">
<resource id="HKT_AdminPortal::cs_portal" title="CS Portal" sortOrder="10" />
<resource id="Magento_Sales::create_new_order" title="Create New Order" sortOrder="20" />
<resource id="Magento_Sales::view_order" title="View Order" sortOrder="30" />
<resource id="Magento_Sales::order_actions" title="Order Actions" sortOrder="40" />
<resource id="Magento_Sales::go_to_archive" title="Go To Order Archive" sortOrder="50" />
</resource>
</resource>
</resource>
</resources>
</acl>
</config>
class Save extends Action
{
public const ADMIN_RESOURCE = 'Magento_Customer::save';
}
module/etc/adminhtml/menu.xml
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Backend:etc/menu.xsd">
<menu>
<add id="Silk_Test::job_head" title="Test" module="Silk_Test" sortOrder="100" parent="Magento_Backend::stores" resource="Silk_Test::job_head" />
<add id="Silk_Test::job" title="Test" module="Silk_Test" sortOrder="20" parent="Silk_Test::job_head" action="test/job" resource="Silk_Test::job" />
</menu>
</config>
// 从已存在的对象中获取
$logger = \Magento\Framework\App\ObjectManager::getInstance()->get(\Psr\Log\LoggerInterface::class);
// 新建一个
$logger = \Magento\Framework\App\ObjectManager::getInstance()->create(\Psr\Log\LoggerInterface::class);
/** @var \Psr\Log\LoggerInterface */
$logger = \Magento\Framework\App\ObjectManager::getInstance()->get('Psr\Log\LoggerInterface');
$logger->warning('=======flg debug=======', ['trace' => $a]);
$logger->warning('=======flg debug=======', ['trace' => $exception->getTrace(), 'msg' => $exception->getMessage()]);
$logger->warning('=======flg debug=======', ['trace' => debug_backtrace()];
$conn = \Magento\Framework\App\ObjectManager::getInstance()->get(\Magento\Framework\App\ResourceConnection::class);
$select = $conn->select()
->from(['so' => $conn->getTableName('sales_order')], [
'so.entity_id',
'so.customer_id',
'soi.fulfilment_end_at',
])
->joinLeft(
['soi' => $conn->getTableName('sales_order_item')],
'so.entity_id=soi.order_id',
);
$select->where("so.status = ?", \Magento\Sales\Model\Order::STATE_PROCESSING)
->where("soi.qty_fulfilled + soi.qty_disabled + soi.qty_markoff < soi.qty_invoiced")
->where("soi.fulfilment_start_at <= ? <= soi.fulfilment_end_at", time());
$result = $conn->fetchAll($select);
// 直接运行 sql 语句
$conn = \Magento\Framework\App\ObjectManager::getInstance()->get(\Magento\Framework\App\ResourceConnection::class);
$result = $conn->getConnection()->query('SELECT TIMEDIFF(NOW(), UTC_TIMESTAMP);')->fetchAll();
通过某一个模型的 collection 对象
/** @var \Magento\Framework\Model\ResourceModel\Db\Collection\AbstractCollection */
$collection = $collectionFactory->create();
$collection->addFieldToSelect(
'*'
)->addFieldToFilter('customer_id', $customer->getId());
/** @var \Magento\Framework\DB\Select $select */
echo $select->__toString();
/** @var \Magento\Framework\Model\ResourceModel\Db\Collection\AbstractCollection $collection */
echo $collection->getSelect()->__toString();
echo $collection->getSelectSql(true);
加在这个文件里 app/etc/env.php 加上这段
'db_logger' => [
'output' => 'file',
'log_everything' => 1,
'query_time_threshold' => '0.001',
'include_stacktrace' => 0
],
日志会输出到这个文件里 var/debug/db.log
vendor\magento\zendframework1\library\Zend\Db\Adapter\Abstract.php query
# region logsql
$logOpen = false;
// $logOpen = true;
$trace = debug_backtrace();
$basePath = BP . DIRECTORY_SEPARATOR;
if (!defined('DEBUG_TRACE_LOG')) {
$logpath = $basePath . 'var' . DIRECTORY_SEPARATOR . 'log' . DIRECTORY_SEPARATOR . 'debug_trace_sql';
if (!is_dir($logpath)) {
mkdir($logpath, 0755, true);
}
define('DEBUG_TRACE_LOG', $logpath . DIRECTORY_SEPARATOR . date('ymdHis') . '.log');
$data = [
'_POST' => $_POST ?? null,
'_GET' => $_GET ?? null,
'_FILES' => $_FILES ?? null,
'_SERVER' => $_SERVER ?? null,
'_SESSION' => $_SESSION ?? null,
'_input' => file_get_contents("php://input"),
// '_stdin' => file_get_contents("php://stdin") // 这一句在命令行里会等待输入
];
$msg = print_r($data, true) . '========' . PHP_EOL;
if ($logOpen) {
file_put_contents(
DEBUG_TRACE_LOG,
$msg,
FILE_APPEND
);
}
}
$ignore = [ // 忽略 ObjectManager 的文件, Interceptor 的文件, Factory 的文件
'vendor' . DIRECTORY_SEPARATOR . 'magento' . DIRECTORY_SEPARATOR . 'framework' . DIRECTORY_SEPARATOR . 'Interception' . DIRECTORY_SEPARATOR . 'Interceptor.php',
'generated',
'vendor' . DIRECTORY_SEPARATOR . 'magento' . DIRECTORY_SEPARATOR . 'framework' . DIRECTORY_SEPARATOR . 'ObjectManager' . DIRECTORY_SEPARATOR . 'Factory',
'vendor' . DIRECTORY_SEPARATOR . 'magento' . DIRECTORY_SEPARATOR . 'framework' . DIRECTORY_SEPARATOR . 'ObjectManager' . DIRECTORY_SEPARATOR . 'ObjectManager.php',
];
$pattern = array_map(function($item) use ($basePath) {
return '(' . preg_quote($basePath . $item, '/') . ')';
}, $ignore);
$pattern = '/' . implode('|', $pattern) . '/im';
$max = 200;
$traceRecord = [];
// $traceRecord[] = __FILE__ . ':' . __LINE__;
for ($i = 0, $len = count($trace); $i < $max && $i < $len; $i++) {
if (isset($trace[$i]['file'])) {
if (!preg_match($pattern, $trace[$i]['file'])) {
$file = $trace[$i]['file'];
$line = $trace[$i]['line'] ?? '1';
$class = $trace[$i]['class'] ?? '';
$func = $trace[$i]['function'] ?? '';
$record = $file . ':' . $line . ' ' . $class . ' ' . $func;
$traceRecord[] = $record;
}
}
}
$msg = print_r([
$sql,
count($bind) < 1 ? null : $bind,
$traceRecord,
], true) . '========' . PHP_EOL;
if ($logOpen) {
$filer = [ // 通过正则表达式只记录某些语句
// '`customer_entity`',
// '`customer_address_entity`',
// '`quote_address`',
// '`salesrule`',
// '`salesrule_coupon`',
// '`salesrule_customer`',
// '^SELECT'
// 'customer_is_guest',
];
$regexp = '';
if (is_array($filer) && count($filer) > 0) {
$filer = implode('|', $filer);
$regexp = '/' . $filer . '/';
}
if (empty($regexp) || filter_var($sql, FILTER_VALIDATE_REGEXP, array("options" => array("regexp" => $regexp)))) {
file_put_contents(
DEBUG_TRACE_LOG,
$msg,
FILE_APPEND
);
}
}
# endregion logsql
这一段是硬写在这个方法里的,也可以硬写到其它方法里
vendor\magento\zendframework1\library\Zend\Db\Adapter\Abstract.php query
通过正则表达式搜索某个接口的实现类或某个对象的继承类
implements(?:.*)ObjectManagerInterface\n
extends(?:.*)AbstractResource\n
搜索时的排除选项
.js,.css,.md,.txt,.json,.csv,.html,.less,.phtml,**/tests,**/test,**/Test,**/setup,**/view,**/magento2-functional-testing-framework,.wsdl,**/module-signifyd,**/Block
app/code/HKT/**/*.php
app/**/*Test.php
magento/**/*.php
修改这个文件的 execute 方法,用 exit(0); 来结束
vendor/magento/module-indexer/Console/Command/IndexerInfoCommand.php
例子
protected function execute(InputInterface $input, OutputInterface $output)
{
$objectMamager = \Magento\Framework\App\ObjectManager::getInstance();
/** @var \Magento\Framework\App\ResourceConnection */
$connection = $objectMamager->get(\Magento\Framework\App\ResourceConnection::class);
$conn = $connection->getConnection();
/** @var \Mageplaza\SocialLogin\Model\Social */
$social = $objectMamager->get(\Mageplaza\SocialLogin\Model\Social::class);
$customer = $social->getCustomerByEmail('qwe@asd.com');
/** @var \Magento\Quote\Model\QuoteFactory */
$quoteFactory = $objectMamager->get(\Magento\Quote\Model\QuoteFactory::class);
$quote = $quoteFactory->create();
$quote->setCustomer($customer->getDataModel());
$address = $quote->getShippingAddress();
var_dump($address->getCity());
exit(0);
$indexers = $this->getAllIndexers();
foreach ($indexers as $indexer) {
$output->writeln(sprintf('%-40s %s', $indexer->getId(), $indexer->getTitle()));
}
}
运行命令
php bin/magento indexer:info
php -d xdebug.remote_autostart=on bin/magento indexer:info
通过命令行运行测试代码,可以不加载前端资源,反馈的速度更快。 修改原本的命令行是为了不运行构建的命令就能生效。 一些对象可以通过 \Magento\Framework\App\ObjectManager::getInstance()->get() 的方法获得。
require('Magento_Checkout/js/model/quote');
sales_order 表的两个状态
遇到问题,可以先搜索一下 github 的 iusses ,同样的问题可能已经出了补丁,不用自己修改。
从 marketplace.magento.com 下载和安装拓展
https://devdocs.magento.com/guides/v2.4/config-guide/cli/config-cli-subcommands-cron.html
https://devdocs.magento.com/guides/v2.4/config-guide/cron/custom-cron.html
查看启用的模块
php bin/magento module:status
启用模块
php bin/magento module:enable 模块名
禁用模块
php bin/magento module:disable 模块名
刷新缓存
php bin/magento cache:clean 清楚缓存
php bin/magento indexer:reindex 刷新全部索引
php bin/magento setup:upgrade 更新数据 Upgrades the Magento application, DB data, and schema
php bin/magento setup:di:compile 编译
php bin/magento setup:static-content:deploy -f 部署静态视图文件
php bin/magento cache:flush 刷新缓存
模块的代码修改后也要刷新缓存
github 里 magento2 的模块例子
生成 magento 模块 https://cedcommerce.com/magento-2-module-creator/
https://devdocs.magento.com/guides/v2.4/extension-dev-guide/module-development.html
http://www.wps.team/book/magento2/