PHP APC缓存安装配置教程
最简单的方法,找到php安装目录的pecl
自动安装
# /usr/local/php/bin/pecl install apc
接下来按提示一步步完成即可
然后配置 /usr/local/php/etc/php.ini 末尾加入
extension=apc.so
手动安装
官网:http://cn2.php.net/manual/zh/book.apc.php
下载:http://pecl.php.net/package/APC 找最新的
下载apc
# wget http://pecl.php.net/get/APC-3.1.13.tgz
# tar -zxvf APC-3.1.13.tgz
# cd APC-3.1.13
生成configure文件
# /usr/local/php/bin/phpize
执行configure 并且make && make install
# ./configure --enable-apc --enable-apc-mmap --with-php-config=/usr/local/php/bin/php-config
# make
# make install
拷贝添加SO文件
# cp /usr/local/php/lib/php/extensions/no-debug-non-zts-20100525/apc.so /usr/local/php/lib/php/extensions/apc.so
# chmod 755 /usr/local/php/lib/php/extensions/apc.so
修改php.ini使之启动APC模块
# vi /usr/local/php/etc/php.ini
extension_dir = "/usr/local/php/lib/php/extensions"
extension=apc.so
apc.enabled = 1
; apc.cache_by_default = on
; apc.shm_segments = 1
; apc.shm_size = 128
; apc.ttl = 7200
; apc.user_ttl = 7200
; apc.num_files_hint = 1024
; apc.write_lock = On
; apc.gc_ttl=3600
; apc.ttl=0
; apc.mmap_file_mask=/tmp/apc.XXXXXX
重启apache
# service httpd restart
使用APC
test.php
<?php
print_r(apc_cache_info());
注意 在浏览器看会不是很友好,可以查看网页源代码就看到很清晰
Array
(
[num_slots] => 1031
[ttl] => 0
[num_hits] => 3
[num_misses] => 1
[num_inserts] => 1
[expunges] => 0
[start_time] => 1398341530
[mem_size] => 4240
[num_entries] => 1
[file_upload_progress] => 1
[memory_type] => mmap
[locking_type] => pthread mutex Locks
[cache_list] => Array
(
[0] => Array
(
[type] => file
[device] => 64768
[inode] => 1179758
[filename] => /data/www/www.111cn.net /test.php
[num_hits] => 3
[mtime] => 1398341609
[creation_time] => 1398341617
[deletion_time] => 0
[access_time] => 1398341630
[ref_count] => 1
[mem_size] => 4240
)
)
[deleted_list] => Array
(
)
[slot_distribution] => Array
(
[109] => 1
)
)
多次点击,可以发现 num_hits 在变化,说明缓存命中了!
压力测试看效果
关闭开启apc分别压力测试对比一下你会发现开启apc之后吞吐率会比没开启apc要提高许多。
# ab -n1000 -c10 http://www.111cn.net /test.php
微信公众平台实现微信网页登陆授权开发其实是非常的简单了,因为官方的参考程序了,下面小编就看了一站长根据官方参考做的一个网页登陆授权例子,大家可看看。文件1:index.php
//换成自己的接口信息
$appid = 'XXXXX';
header('location:https://open.weixin.qq.com/connect/oauth2/authorize?appid='.$appid.'&redirect_uri=127.0.0.1/oauth.php&response_type=code&scope=snsapi_userinfo&state=123&connect_redirect=1#wechat_redirect');
参数说明:
参数
|
是否必须
|
说明
|
appid | 是 | 公众号的唯一标识 |
redirect_uri | 是 | 授权后重定向的回调链接地址,请使用urlencode对链接进行处理 |
response_type | 是 | 返回类型,请填写code |
scope | 是 | 应用授权作用域,snsapi_base (不弹出授权页面,直接跳转,只能获取用户openid),snsapi_userinfo (弹出授权页面,可通过openid拿到昵称、性别、所在地。并且,即使在未关注的情况下,只要用户授权,也能获取其信息) |
state | 否 | 重定向后会带上state参数,开发者可以填写a-zA-Z0-9的参数值 |
#wechat_redirect | 是 | 无论直接打开还是做页面302重定向时候,必须带此参数 |
文件二:oauth.php
代码如下 | 复制代码 |
<?php $code = $_GET['code']; $state = $_GET['state']; //换成自己的接口信息 $appid = 'XXXXX'; $appsecret = 'XXXXX'; if (empty($code)) $this->error('授权失败'); $token_url = 'https://api.weixin.qq.com/sns/oauth2/access_token?appid='.$appid.'&secret='.$appsecret.'&code='.$code.'&grant_type=authorization_code'; $token = json_decode(file_get_contents($token_url)); if (isset($token->errcode)) { echo '<h1>错误:</h1>'.$token->errcode; echo '<br/><h2>错误信息:</h2>'.$token->errmsg; exit; } $access_token_url = 'https://api.weixin.qq.com/sns/oauth2/refresh_token?appid='.$appid.'&grant_type=refresh_token&refresh_token='.$token->refresh_token; //转成对象 $access_token = json_decode(file_get_contents($access_token_url)); if (isset($access_token->errcode)) { echo '<h1>错误:</h1>'.$access_token->errcode; echo '<br/><h2>错误信息:</h2>'.$access_token->errmsg; exit; } $user_info_url = 'https://api.weixin.qq.com/sns/userinfo?access_token='.$access_token->access_token.'&openid='.$access_token->openid.'&lang=zh_CN'; //转成对象 $user_info = json_decode(file_get_contents($user_info_url)); if (isset($user_info->errcode)) { echo '<h1>错误:</h1>'.$user_info->errcode; echo '<br/><h2>错误信息:</h2>'.$user_info->errmsg; exit; } //打印用户信息 echo '<pre>'; print_r($user_info); echo '</pre>'; ?> |
参数
|
描述
|
openid | 用户的唯一标识 |
nickname | 用户昵称 |
sex | 用户的性别,值为1时是男性,值为2时是女性,值为0时是未知 |
province | 用户个人资料填写的省份 |
city | 普通用户个人资料填写的城市 |
country | 国家,如中国为CN |
headimgurl | 用户头像,最后一个数值代表正方形头像大小(有0、46、64、96、132数值可选,0代表640*640正方形头像),用户没有头像时该项为空 |
privilege | 用户特权信息,json 数组,如微信沃卡用户为(chinaunicom) |
unionid | 只有在用户将公众号绑定到微信开放平台帐号后,才会出现该字段。详见:获取用户个人信息(UnionID机制) |
到此网页登陆授权开发功能就作完了,如果想要获取用户基本信息我们需要看另一个例子,在官方有说明大家可自行搜索哦。
本教程来详解Drupal的Authcache缓存模块的缓存机制原理。Drupal带有内置的缓存模块:Boost、Authcache,但是这两个模块的原理不同,boost是生成静态页面,Authcache是生存页面缓存。相关文章:Drupal的模块高级应用之Authcache-动态加载内容教程
Authcache模块和Boost模块的原理不一样,Boost模块是生成静态页面,所以缓存的效果最好,速度最快。Authcache模块是利用Drupal自身的缓存机制,生成页面缓存,由于进入到了Drupal环节,因此速度没有Boost缓存快,但是优点就是可以灵活的使用PHP/Drupal相关方法,动态处理数据。
首先,我们从Drupal的bootstrap讲起。
function drupal_bootstrap($phase = NULL, $new_phase = TRUE) {
// Not drupal_static(), because does not depend on any run-time information.
static $phases = array(
DRUPAL_BOOTSTRAP_CONFIGURATION,
DRUPAL_BOOTSTRAP_PAGE_CACHE,
DRUPAL_BOOTSTRAP_DATABASE,
DRUPAL_BOOTSTRAP_VARIABLES,
DRUPAL_BOOTSTRAP_SESSION,
DRUPAL_BOOTSTRAP_PAGE_HEADER,
DRUPAL_BOOTSTRAP_LANGUAGE,
DRUPAL_BOOTSTRAP_FULL,
);
….
}
这是Drupal自带的bootstrap的几个环节(Drupal7),从CONFIGURATION、一直到 FULL,这样整个Drupal就启动了,所有的模块也加载了。
其中我们发现,有一个环节叫 PAGE_CACHE,我们来把这个阶段的处理函数完整的贴出来,以便大家能更好的理解这段代码。
function _drupal_bootstrap_page_cache() {
global $user;
// Allow specifying special cache handlers in settings.php, like
// using memcached or files for storing cache information.
require_once DRUPAL_ROOT . '/includes/cache.inc';
foreach (variable_get('cache_backends', array()) as $include) {
require_once DRUPAL_ROOT . '/' . $include;
}
// Check for a cache mode force from settings.php.
if (variable_get('page_cache_without_database')) {
$cache_enabled = TRUE;
}
else {
drupal_bootstrap(DRUPAL_BOOTSTRAP_VARIABLES, FALSE);
$cache_enabled = variable_get('cache');
}
drupal_block_denied(ip_address());
// If there is no session cookie and cache is enabled (or forced), try
// to serve a cached page.
if (!isset($_COOKIE[session_name()]) && $cache_enabled) {
// Make sure there is a user object because its timestamp will be
// checked, hook_boot might check for anonymous user etc.
$user = drupal_anonymous_user();
// Get the page from the cache.
$cache = drupal_page_get_cache();
// If there is a cached page, display it.
if (is_object($cache)) {
header('X-Drupal-Cache: HIT');
// Restore the metadata cached with the page.
$_GET['q'] = $cache->data['path'];
drupal_set_title($cache->data['title'], PASS_THROUGH);
date_default_timezone_set(drupal_get_user_timezone());
// If the skipping of the bootstrap hooks is not enforced, call
// hook_boot.
if (variable_get('page_cache_invoke_hooks', TRUE)) {
bootstrap_invoke_all('boot');
}
drupal_serve_page_from_cache($cache);
// If the skipping of the bootstrap hooks is not enforced, call
// hook_exit.
if (variable_get('page_cache_invoke_hooks', TRUE)) {
bootstrap_invoke_all('exit');
}
// We are done.
exit;
}
else {
header('X-Drupal-Cache: MISS');
}
}
}
当我们看到最下面,exit ;(We are done)之处,我们就知道,Drupal已经处理完了请求,后面的环境(Session、数据库、模块、FULL)等环节就不用启动了,因此大大节省了服务器的处理时间和提高了响应时间。
这就是Drupal自带的缓存处理机制!!
Drupal自带的缓存机制缺点也很明显,就是只对匿名用户有效。
因此,Authcache模块就出现了,Authcache就是利用Drupal自带的缓存机制,实现对登录用户的缓存。
继续看上面的代码,其中有3行,如下:
foreach (variable_get('cache_backends', array()) as $include) {
require_once DRUPAL_ROOT . '/' . $include;
}
其中,获取’cache_backends’的时候,加载了一个数组变量,所以在Drupal自身的缓存阶段要使用到authcache,那就必须修改这个 cache_backends。
果如其然,如下所示,我们在安装authcache的时候,就必须设置如下变量。
$conf['cache_backends'][] = 'sites/all/modules/authcache/authcache.cache.inc';
$conf['cache_backends'][] = 'sites/all/modules/authcache/modules/authcache_builtin/authcache_builtin.cache.inc';
这个时候,我们就加载进了authcache.cache.inc和文件了。
继续…
我们打开authcache.cache.inc 其中,就是定义一些函数。
继续查看authcache_builtin.cache.inc文件,看到如下代码:
$delivered = authcache_builtin_cacheinc_retrieve_cache_page();
if ($delivered) {
exit;
}
也就是说在这个时候,如果命中了缓存就直接输入页面内容,不再继续boot!这个地方也就代替了原本Drupal自己查找缓存和计算命中缓存的逻辑,使用authcache自己的算法,根据用户的角色不同,使用的缓存不同。
这就是authcache的核心!
当然authcache还可以做更多,比如,
1. 根据用户不同,生产不同的缓存(需要处理)。
2. 配合authcache_p13n模块,动态处理某些局部页面,比如某个block。
3. 修改缓存的某个些内容。(稍后会详细讲解)
等等,这就是authcache比boost灵活的地方,当然也是缺点,需要调用很多PHP、数据库等等,肯定比boost慢一些。
相关文章:Drupal模块讲解-Authcache缓存原理详解教程
本文讲一下如果通过修改authcache的核心代码,来实现缓存页面的个性化内容。
高级应用之Authcache-动态加载内容教程" />
通用的缓存,或多或少都是要进行个性化处理的,比如用户名显示、动态加载用户资料、用户好友等等。
一般情况下,这种局部个性化,都是通过两种手段实现:一个是SSI,另一个是CSI。
Authcache本身可以实现局部personalization, 模块叫p13n。
Authcache的ajax模块属于CSI,ESI模块应该是属于SSI,但是由于ESI模块需要搭建varnish服务器,配置VCL,加上服务器的设置问题,会导致ESI容易出错,并且本身ESI传递cookie也会有些问题,因此ESI实际上实现起来相当复杂。
所以,如果我们要使用服务器端的personalization,通过PHP修改根据某些条件修改某些内容的话,需要hack一些authcache的代码。
1. autcache.module文件
找到下面一句,Line 188
// Invoke cache backends and serve page.
修改成如下:
代码如下 | 复制代码 |
// Invoke cache backends and serve page. if (authcache_page_is_cacheable()) { $cache = authcache_backend_cache_save(); authcache_serve_page_from_cache($cache, authcache_key()); } else { ////process html result global $conf; $conf['page_compression'] = FALSE; $cache = new stdClass(); ////process html result $cache->data['body'] = ob_get_contents(); ob_clean(); foreach (variable_get('authcache_page_process', array()) as $include) { require_once DRUPAL_ROOT . '/' . $include; } foreach (variable_get('authcache_page_process_interface', array()) as $process) { require_once DRUPAL_ROOT . '/' . $include; if (is_callable($process)) { $process($cache); } } echo $cache->data['body']; } exit; } |
其中,主要是加了else后面的处理代码。
2. authcache.cache.inc文件
从85行开始,到函数结尾,修改成如下格式。
代码如下 | 复制代码 |
$return_compressed = FALSE; ///NEW //Don't send compressed content if ($page_compression) { header('Vary: Accept-Encoding', FALSE); // If page_compression is enabled, the cache contains gzipped data. if ($return_compressed) { // $cache->data['body'] is already gzip'ed, so make sure // zlib.output_compression does not compress it once more. ini_set('zlib.output_compression', '0'); header('Content-Encoding: gzip'); } else { // The client does not support compression, so unzip the data in the // cache. Strip the gzip header and run uncompress. $cache->data['body'] = gzinflate(substr(substr($cache->data['body'], 10), 0, -8)); } } ///NEW foreach (variable_get('authcache_page_process', array()) as $include) { require_once DRUPAL_ROOT . '/' . $include; } foreach (variable_get('authcache_page_process_interface', array()) as $process) { if (is_callable($process)) { $process($cache); } } |
注意,有两个地方,///NEW 标注,表示新加的内容,中间有一段是原有的code。
改完之后,我们就完工了。
如何使用呢?
新建一个文件,比如在custom模块下面,叫custom_authcache.inc,黏贴如下代码:
代码如下 | 复制代码 |
<?php /** Add the following lines to settings.php $conf['authcache_page_process'][] = 'sites/all/modules/custom/custom/custom_authcache.inc'; $conf['authcache_page_process_interface'][] = 'custom_authcache_common_process'; If you want to add more process interface, add your function name as an item in this array, $conf['authcache_page_process_interface']. If you want to include file, please add file name to this array, $conf['authcache_page_process'] Core Changes: modules/authcache/authcache.cache.inc modules/authcache/authcache.module **/ /* * Process authcache content to replace content */ function custom_authcache_common_process(&$cache) { $cache->data['body'] = str_ireplace('<span id="replace_placeholder_1"/>', _get_real_data(), $cache->data['body']); } |
看上面的注释,复制两行代码到settings.php文件。
具体的说明注释已经很详细了,相信应该没问题。
这样,这个custom_authcache_common_process函数就可以动态替换HTML里面的内容了,达到了个性化页面的目的。
上一教程:Drupal8模块开发之路由、控制器和菜单链接教程
在本教程中,我们将学习进一步的开发,我们可以在这个库 (link is external)里找到我们需要的沙盒模块代码示例,里面两个重要的新功能:区块和表单。
为此,我们将创建一个自定义区块来返回一些可配置的文本,在那之后,我们将创建 一个简单的表单来打印输出用户提交到的数据到屏幕上。
不知道怎么下载这个库的同学看这里:
Drupal8 区块
在Drupal8里,有一个很酷的新变化时,以往的Block(区块) API 已经转换成了插件的形式(一个全新的概念),这意味着区块将是可被重复使用的功能块(在引擎下),
你现在可以在后台UI界面创建一个Block区块,并在整个网站的任何地方重用它,你现在不会再局限于只能使用一次这个区块。
让我们先创建一个简单的区块来打印"Hello World"到屏幕上! 一般情况下,我们首先需要在模块根文件夹下的src/Plugin/Block目录下创建一个class类
文件DemoBlock.php,我们这里暂且把这个新的区块命名为"DemoBlock", 所以你最终在这个文件中,看到的代码会是像这样:
代码如下 | 复制代码 |
<?php namespace DrupaldemoPluginBlock; use DrupalblockBlockBase; use DrupalCoreSessionAccountInterface; /** * Provides a 'Demo' block. * * @Block( * id = "demo_block", * admin_label = @Translation("Demo block"), * ) */ class DemoBlock extends BlockBase { /** * {@inheritdoc} */ public function build() { return array( '#markup' => $this->t('Hello World!'), ); } /** * {@inheritdoc} */ public function access(AccountInterface $account) { return $account->hasPermission('access content'); } } |
像所有其他的class类文件一样,我们要先在开始时先声明类的命名空间。然后,我们使用BlockBase类以便于我们等下可以继承和扩展它,以及也需要使用AccountInterface类以便于让我们可以获取当前登录的用户。然后接下来的一些代码你肯定没有在Drupal 7见过,这就是:annotations注释。
Annotations注释是一个PHP发现工具,使用这些注释,我们可以让Drupal知道我们想注册一个新的区块(@ Block),我们设定了Id号:demo_block 和admin_label :Demo block(这些注视将会通过注视翻译系统被drupal识别)。
接下来,我们在DemoBlock类里扩展下BlockBase类,我们将实现两个方法(都是最常见的),build()方法是最重的,因为它返回一个可打印的区块信息数组,access()方法控制查看此区块的访问权限,这里传递给它的参数是AccountInterface类的一个实例,在这里,实际传递的就是当前用户信息参数。
另外一个有趣的事情需要注意的是,我们不再像以前一样使用全局t()函数直接翻译文本了,但是我们会继承使用父类的t()方法,所以你看到的是$this->t().
就是这样,你现在可以清空缓存,然后进入区块的配置页,最酷的是你现在已经成功创建了一个区块,并且你可以把这个区块放在任何网站里你设定的regions区域。
Drupal 8 区块配置
现在我们已经知道了如何创建一个新的区块,让我们进一步学习下如何用API为它添加配置表单,我们将让你可以编辑此区块,给你一个文本输入框,让你可以输入一个名字,然
后前台就会显示"Hello 名字"来替换 "Hello World".
首先,我们需要定义一个文本框,所以在我们的DemoBlock类里,我们可以添加一个新的方法叫做blockForm():
代码如下 | 复制代码 |
/** * {@inheritdoc} */ public function blockForm($form, &$form_state) { $form = parent::blockForm($form, $form_state); $config = $this->getConfiguration(); $form['demo_block_settings'] = array( '#type' => 'textfield', '#title' => $this->t('Who'), '#description' => $this->t('Who do you want to say hello to?'), '#default_value' => isset($config['demo_block_settings']) ? $config['demo_block_settings'] : '', ); return $form; } |
这个表单API应该看起来很熟悉,似乎和以往的drupal 7里的差不多,然而,细看之下,你会发现有一些新的东西在里面,首先,我们从父类里获取$form数组(所以我们是在已存在
的表单基础上新增创建我们的字段),标准的面向对像,然后,我们通过BlockBase类定义的getConfiguration()方法来获取配置信息,并且我们把demo_block_settings的值作为了
#default_value的默认值.
接下来,到了我们要对我们传递的字段值进行提交处理并保存进区块配置里的时候了:
代码如下 | 复制代码 |
/** * {@inheritdoc} */ public function blockSubmit($form, &$form_state) { $this->setConfigurationValue('demo_block_settings', $form_state['values']['demo_block_settings']); } |
这个方法也存在于DemoBlock类里,它被用于保存demo_block_settings的值(请注意保持键名的一致性)
最后我们需要调整我们的build()方法,让它在打印Hello时包含name名字:
代码如下 | 复制代码 |
/** * {@inheritdoc} */ public function build() { $config = $this->getConfiguration(); if (isset($config['demo_block_settings']) && !empty($config['demo_block_settings'])) { $name = $config['demo_block_settings']; } else { $name = $this->t('to no one'); } return array( '#markup' => $this->t('Hello @name!', array('@name' => $name)), ); } |
现在,这应该看起来相当容易,我们获取区块的配置信息,如果我们的字段值存在,我们就把它打印出来,如果不存在,就打印"to no one", 你现在可以清空缓存后,编辑区块,填写一个值,然后保存,然后你就能在前台看到" Hello + 名字值"了。
Drupal 8 表单
最后,我们将在本教程中,探讨如何创建一个简单的表单,由于空间的限制,我不会覆盖它的配置管理(通过表单提交存储值),相反,我将举例说明一个简单的表单设定,然后让提交的值简单的打印在屏幕上,以演示它可以正常工作。
在Drupal 8 里,表单定义函数都在一个class类里被组织在一起,所以让我们定义一个简单的DemoForm类,在src/Form/DemoForm.php中:
代码如下 | 复制代码 |
<?php /** * @file * Contains DrupaldemoFormDemoForm. */ namespace DrupaldemoForm; use DrupalCoreFormFormBase; class DemoForm extends FormBase { /** * {@inheritdoc}. */ public function getFormId() { return 'demo_form'; } /** * {@inheritdoc}. */ public function buildForm(array $form, array &$form_state) { $form['email'] = array( '#type' => 'email', '#title' => $this->t('Your .com email address.') ); $form['show'] = array( '#type' => 'submit', '#value' => $this->t('Submit'), ); return $form; } /** * {@inheritdoc} */ public function validateForm(array &$form, array &$form_state) { if (strpos($form_state['values']['email'], '.com') === FALSE ) { $this->setFormError('email', $form_state, $this->t('This is not a .com email address.')); } } /** * {@inheritdoc} */ public function submitForm(array &$form, array &$form_state) { drupal_set_message($this->t('Your email address is @email', array('@email' => $form_state['values']['email']))); } } |
除了OOP思想的改变,一切应该看起来像以前的drupal 7 一样熟悉。Form API 仍然基本没有什么变化(除了一些新的表单元素的加入和相关class类的封装),所以会发生什么?
首先,我们使用了命名空间的类和核心的FormBase类,所以接下来我们就可以在我们自己的DemoForm类里扩展它,然后我们实现了4个方法,其中3个应该是很熟悉的。 getFormid()方法是新增的并且是必须要有的,这个方法用于简单的返回form的机器名称,buildForm()方法也是必须要有的,它用于构建一个表单,怎么用?其实就和你之前在drupal 7中的构建方法差不多,validateForm()方法是可选的,它像drupal 7里一样,用于验证表单提交数据,最后,submitForm()方法用于处理提交的表单数据,一切是不是很合乎逻辑组织。
所以,我们想用这个表单实现什么?我们有一个email邮件字段(Drupal 8的新表单元素),我们希望用户填写它,默认情况下,Drupal会检查是否输入了一个正确的邮箱格式的值,但在我们的验证函数里我们会确保它是一个合法的带.com后缀的邮箱地址,如果不是,我们会在字段上设置了一个错误提示,最后提交处理,然后打印一个提示消息在网页上。
为了使用这个表单,我们需要做最后一件事,就是提供为这个表单提供一个路由,所以请编辑demo.routing.yml文件,并增加以下代码:
代码如下 | 复制代码 |
demo.form: path: '/demo/form' defaults: _form: 'DrupaldemoFormDemoForm' _title: 'Demo Form' requirements: _permission: 'access content' |
这应该看起来很熟悉,因为我们之前有篇文章介绍过怎么路由一个简单页面,唯一最大的区别是, 在 defaults下面,我们用_form替代了之前的_content,并为_form指定了一个表单类,
这个类就是刚刚我们创建的。
清空缓存后就可以输入地址导航到demo/form,然后就可以看到这个表单并测试它。
如果你熟悉以前drupal 7中的drupal_get_form,也知道怎样加载一个表单的方式,因此,你就可以使用drupal 8中的全局Drupal类 (link is external),比如formBuilder()方法来获取一个表单,像这样
代码如下 | 复制代码 |
$form = Drupal::formBuilder()->getForm('DrupaldemoFormDemoForm'); |
然后你就可以返回$form 并渲染输出了。
结论
在这篇文章中,我们继续探索了Drupal 8模块开发的两个新的话题:区块和表单。我们已经看到了如何创建我们自己的区块(然后你就可以在区块管理界面创建新区块)。我们还学会了如何添加和存储一个自定义的配置值(这个值你可以在稍后使用它)。在表单的话题中,我们看到了一个简单的FormBase类的实现,我们用来把用户提交的数据打印到屏幕上。
相关文章
- 编译安装非常的简单了我们现在的php版本已经到了php7了,下文小编来为各位介绍一篇关于PHP7快速编译安装的步骤,希望文章能够帮助到各位。 一、安装必要一些依赖 yum...2016-11-25
- 如果我们需要安培Laravel4的话最php最低要求要在php5.3.7版本并且我们需要把mcrypt与openss这两个扩展开启才可以,具体步骤我们参考下文。 前面我们介绍我了 com...2016-11-25
- 这篇文章主要介绍了c#自带缓存使用方法,包括获取数据缓存、设置数据缓存、移除指定数据缓存等方法,需要的朋友可以参考下...2020-06-25
- 这篇文章主要介绍了Rstudio中安装package出现的问题及解决方案,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-05-06
- 这篇文章主要介绍了IDEA中的clean,清除项目缓存图文教程,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-09-25
- PHP-FPM我们相信各位用高版本的php经常使用到了,下面整理了一些关于PHP-FPM的笔记,有兴趣的可进来看看。 今天赶上了123System OPenVZ VPS全场半价的机会,购入了一...2016-11-25
安装和使用percona-toolkit来辅助操作MySQL的基本教程
一、percona-toolkit简介 percona-toolkit是一组高级命令行工具的集合,用来执行各种通过手工执行非常复杂和麻烦的mysql和系统任务,这些任务包括: 检查master和slave数据的一致性 有效地对记录进行归档 查找重复的索...2015-11-24Linux安装Pytorch1.8GPU(CUDA11.1)的实现
这篇文章主要介绍了Linux安装Pytorch1.8GPU(CUDA11.1)的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-03-25- 这篇文章主要介绍了vscode安装git及项目开发过程,本文通过图文并茂的形式给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2021-05-19
- 这篇文章主要为大家详细介绍了Visual Studio 2015下载和安装图文教程,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2021-09-22
- 现在我们介绍一种在Node下检查简单错误的JS代码验证工具JSHint。 JSHint的具体介绍参考http://www.jshint.com/about/,说直白点儿,JSHint就是一个检查JS代码规范与否的工具,它可以用来检查任何(包括server端和client端...2014-05-31
Centos中彻底删除Mysql(rpm、yum安装的情况)
我用的centos6,mysql让我整出了各种问题,我想重装一个全新的mysql,yum remove mysql-server mysql之后再install并不能得到一个干净的mysql,原来的/etc/my.cnf依然没变,datadir里面的数据已没有任何变化,手动删除/etc/my.cn...2015-03-15- 这篇文章主要介绍了在PyCharm中安装PaddlePaddle的方法,本文给大家介绍的非常想详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2021-02-05
Ubuntu20.04安装cuda10.1的步骤(图文教程)
这篇文章主要介绍了Ubuntu20.04安装cuda10.1的步骤(图文教程),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-07-30- 这篇文章主要介绍了linux服务器快速卸载安装node环境(简单上手),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-02-22
Postman安装与使用详细教程 附postman离线安装包
这篇文章主要介绍了Postman安装与使用详细教程 附postman离线安装包,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2021-03-05- 这篇文章主要给大家介绍了关于iOS蓝牙设备名称缓存问题的解决方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-12-08
- 这篇文章主要介绍了uni-app从安装到卸载的入门教程,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-05-15
- 这篇文章主要介绍了vs2019安装和使用详细图文教程,本文通过图文并茂的形式给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2020-06-25
- 这篇文章主要介绍了AngularJS实现Model缓存的方式,分享了多种AngularJS实现Model缓存的方法,感兴趣的小伙伴们可以参考一下...2016-02-05