piotrpolak/pepiscms

内容管理系统

1.0.4 2023-04-26 20:14 UTC

This package is auto-updated.

Last update: 2024-09-03 21:11:42 UTC


README

PHP Build Maintainability

PepisCMS是一个内容管理系统。其主要特点是CRUD模块生成器,这使得在几分钟内轻松设置整个基于数据库模式定义的管理面板。生成的管理面板由模块组成,这些模块可以进一步自定义(或者如果你不关心展示细节,也可以保持原样)。

该应用被设计为在CodeIgniter框架之上的核心库,并且允许在不改变或仅作最小更改的情况下进行替换/升级项目代码。

PepisCMS Dashboard

实时演示

演示应用程序已自动部署到Heroku,可访问

演示应用程序的源代码可在https://github.com/piotrpolak/pepiscms-demo找到。

请注意,每次部署新版本时,演示部署的内容都会自动清理。

设置本地开发环境

PepisCMS旨在作为库使用。可以初始化一个带有示例项目的本地开发环境作为Docker Compose环境

docker-compose up

启动Docker Compose设置后,所有PepisCMS实例项目文件都将存储在tmp/目录中。

要重新启动环境,首先删除实例文件,然后重新创建Docker Compose设置

sudo rm -rf ./tmp/ && docker-compose up --force-recreate --build

默认管理员凭据是demo@example.com / demodemo

查看其他有用的开发命令

一些历史

PepisCMS始于2007年作为课程项目。在首次发布后不久,该系统就被用于为几个生产网站和CRM系统提供服务。

CodeIgniter被选为应用程序框架。当时,可用的PHP框架很少,CodeIgniter似乎是合理的选择。

在项目生命周期中,PepisCMS已经流畅地从CodeIgniter版本CI 1.5.4迁移到3.1+。应该注意的是,使用一个pre-PSR框架意味着所有实现都紧密耦合到框架库中。

由于最小占位符和框架的零开销,建立在PepisCMS之上的项目确实非常快。

没有计划将PepisCMS迁移到使用CodeIgniter 4作为框架,因为该框架引入了不兼容的更改。

开发理念

项目采用了非常保守的开发方法,在发布稳定版本之前,已在多个部署上手动测试。结合Behat和PHPUnit测试,使其回归到最低。

成为开源项目

在“10岁生日”之际,该项目以MIT许可证的形式作为开源项目发布,许可证可在以下链接查看:MIT许可证

在将项目推送到GitHub之前,其代码已进行轻微重构,清除了所有专有代码,并添加了一些测试描述,作为一个composer依赖项发布。

随着第一个开源版本的发布,PepisCMS 1.0.0获得了对Composer依赖管理的支持,核心功能通过Behat功能测试进行描述。

部分代码已重写为PSR风格,并从PSR类自动加载中受益。作为一个composer模块,PepisCMS现在受益于组件管理。升级其任何依赖项现在简化为增加composer版本。1.0.*版本与PHP5和PHP都兼容良好。截至2021年,该项目是完全功能和*经过良好测试的。

特性

  • 模块化

    模块化和一致性。外部模块可以独立于系统核心编写。系统核心可以在任何时间不修改当前应用程序的情况下升级。

    有两种类型的模块:内置模块(在所有项目中可用)和用户空间模块。模块可以通过管理控制台启用或禁用。一个典型的模块由管理器和公共控制器以及支持代码组成。

    更多关于模块的信息。

  • 高级用户和用户权限管理

    用户在业务实体上获得一定的权限。每个控制器方法都与一定实体的最小权限相关联。

    所有违反安全策略的行为都会报告在系统审计日志中。

    您可以创建任意数量的用户,可以将用户分配给多个组,安全策略可以在运行时修改。

    更多关于安全策略的信息。

  • 审计日志

    所有用户操作和意外应用程序行为都可以使用高级日志实用程序进行追踪。PepisCMS提供了日志API和用于分析系统日志的控制台。

  • 用户会话安全性

    用户会话在一个小时的不活跃后将过期(可配置)。每次系统验证用户权限时,都会通过验证IP来保护会话免受会话欺骗攻击。

  • 基于Web的文件管理器

    用户可以使用AJAX文件管理器管理服务器上的文件。您可以从配置中限制允许的上传文件扩展列表。

  • 增强的SMTP邮件发送器

    一个用于可靠发送电子邮件的实用程序。当系统无法连接到远程SMTP服务器时,将使用替代的mail网关,并在审计日志中报告回退操作。

  • 多语言原生支持

    该应用程序默认支持国际化和多语言支持,包括前端和后端。一个集成的翻译器可以加快多语言应用程序的开发。

  • 富文本编辑器

    CKEditor使您在编辑网站内容时感觉就像在使用MS Word。您可以更改文本格式并附加图片。

  • 启动时的配置测试

    基本配置测试确保系统在任何环境中都具有凝聚力和正常运行。

  • 两级缓存机制

    使您的网站坚不可摧。HTML输出缓存机制在框架初始化之前运行,以静态页面服务的速度提供静态内容。

  • 备份工具

    允许创建和下载MySQL SQL转储。

  • 内部网络选项

    您可以限制未经身份验证的用户对公共内容和上传文件的访问。

  • SEO友好

    PepisCMS生成SEO友好的链接和优化元标签。它还自动为网站生成网站地图(txt和xml格式)。

  • 用于生成网格和表单的内置组件。

    使用这些组件,您可以从一开始就实现90%的请求功能。数据网格支持按任何列排序表格并实现多个过滤器。《表单生成器》默认实现验证、数据检索和数据保存、文件上传等功能。

    您可以使用高级回调(生命周期回调)扩展或覆盖这些组件的行为。

  • 用于生成Excel文件和PDF文件的内置助手。

    您可以将应用程序数据轻松导出到XLS文件或打印任何HTML到PDF。

  • 内容日志记录

    使得跟踪实体上的更改并恢复特定值变得简单。

  • CRUD模块生成器

    几分钟内生成数据库CRUD管理面板。

    了解更多关于CRUD模块生成器的信息。

  • 内置UI翻译器

    无需努力即可本地化您的应用程序。

    了解更多关于翻译模块的信息。

  • 内置SQL控制台

    使维护和升级任务变得简单。

    了解更多关于SQL控制台模块的信息。

  • 无缝Symphony2集成

    在CMS面板中消费Symphony2封装的业务逻辑。利用强大的依赖注入引擎的优势。

  • 管理面板定制

    通过提供在视图的选定部分注入HTML/JS/CSS代码的可能性,使管理面板的外观定制成为可能。

  • 向下兼容性

    任何PepisCMS实例都可以轻松升级到新版本,而无需花费太多精力。同一分支内的所有版本都是100%向下兼容的。

  • 缓存和管理面板速度

    管理面板的关键组件被缓存,从而提高了CMS的整体性能。

  • Twig集成

  • SSH和数组模型

    使操作提供数据来源的任何模型成为可能。

  • Google Chart集成

  • phpCAS/natvie身份验证驱动程序

    默认情况下禁用了phpCAS身份验证驱动程序。

要求

  • PHP 5.6+/7.0+/8.0,mysqli,gd(推荐),mbstring(推荐)
  • Apache 2与mod_rewrite
  • MySQL或MariaDB数据库
  • composer

安装

PepisCMS作为composer依赖项安装,然后在该用户目录中实例化。

一旦配置并下载了composer依赖项(见下文),有两种方法可以引导PepisCMS实例:

配置composer

从命令行添加composer依赖项()

composer require piotrpolak/pepiscms --prefer-dist

从命令行配置composer(使用GitHub存储库中的dev-master)

composer init --type "project" --stability "dev" \
    --repository '{"type": "vcs", "url": "https://github.com/piotrpolak/pepiscms.git"}' && \
    composer require piotrpolak/pepiscms dev-master --prefer-dist

手动创建composer.json(使用GitHub存储库中的dev-master)

{
    "name": "yourvendorname/yourprojectname",
    "minimum-stability": "dev",
    "repositories": [
        {
            "type": "vcs",
            "url": "https://github.com/piotrpolak/pepiscms.git"
        }
    ],
    "require": {
        "piotrpolak/pepiscms": "dev-master"
    }
}

有指导的安装(用户)

  1. 安装composer依赖项

    composer install --prefer-dist
  2. install.php文件复制到根目录

    cp ./vendor/piotrpolak/pepiscms/install.php ./
  3. 在浏览器中打开install.php https:///install.php

    这将创建一个基本的框架结构。请按照安装指南进行操作。

    • 目录视图 目录视图

    • 复制文件并创建框架结构 复制文件

    • 数据库连接设置

      有两种选项:本地Symfony导入

      选择本地时,您将被要求输入数据库主机、名称、用户名和密码。

      如果选择Symfony导入,则PepisCMS将尝试自动解析Symfony parameters.yml配置。

      Database connection

    • 选择授权驱动。您可以选择本地(用户本地管理)或CAS

      选择CAS时,用户密码将不会由PepisCMS管理。在第一次用户认证(使用系统)时将创建具有最小访问权限的本地用户。

      Authorization driver

    • 配置管理员账户 管理员账户

    • 配置站点选项 站点配置

    • 配置已安装的模块

      您可以选择要安装的模块,并将指定的模块添加到菜单和/或工具中。

      Installed modules

    • 成功消息 成功

    • 仪表板 仪表板

无人值守安装

PepisCMS可以以无人值守的方式进行安装和配置。

以下BASH变量可用于控制安装参数

# The variable values are empty by default. The below values are taken from docker-compose.yml file
PEPIS_CMS_DATABASE_CONFIG_TYPE: native
PEPIS_CMS_DATABASE_HOSTNAME: db
PEPIS_CMS_DATABASE_USERNAME: pepiscms
PEPIS_CMS_DATABASE_PASSWORD: pepiscms
PEPIS_CMS_DATABASE_DATABASE: pepiscms
PEPIS_CMS_AUTH_DRIVER: native
PEPIS_CMS_AUTH_EMAIL: demo@example.com
PEPIS_CMS_AUTH_PASSWORD: demodemo
PEPIS_CMS_SITE_EMAIL: demo@example.com
PEPIS_CMS_SITE_NAME: Demonstration
PEPIS_CMS_OBJECT_CACHE_OBJECT_IS_ENABLED: true # Set false for cloud deployment
PEPIS_CMS_IS_UNATTENDED_INSTALL: true # Set false for manual installer
PEPIS_CMS_EMAIL_USE_SMTP: true
PEPIS_CMS_EMAIL_SMTP_HOST: fake-smtp
PEPIS_CMS_EMAIL_SMTP_USER: fake-smtp
PEPIS_CMS_EMAIL_SMTP_PASS: fake-smtp
PEPIS_CMS_EMAIL_SMTP_PORT: 25

https://:60500下可用电子邮件控制台

无人值守安装的命令行

composer install --prefer-dist && \
    cp vendor/piotrpolak/pepiscms/pepiscms/resources/config_template/template_index.php ./index.php && \
    sed -i -e 's/TEMPLATE_VENDOR_PATH/\.\/vendor\//g' ./index.php && \
    cp vendor/piotrpolak/pepiscms/pepiscms/resources/config_template/template_.htaccess ./.htaccess && \
    php index.php tools install && \
    php index.php tools register_admin $PEPIS_CMS_AUTH_EMAIL $PEPIS_CMS_AUTH_PASSWORD

请参阅演示应用程序设置脚本以查看PepisCMS无人值守安装的实际操作。

命令行界面

可用的命令行工具

  • php index.php tools install [<clean_database>]
  • php index.php tools register_admin <email> <password>
  • php index.php tools passwd <email> <password>
  • php index.php tools inactivate <email>
  • php index.php tools activate <email>
  • php index.php tools set_config <name> <value>
  • php index.php tools get_config <name>
  • php index.php tools index - 列出所有命令

模块

PepisCMS区分两种类型的模块,基于模块代码放置的位置

  • 系统模块 - 这些模块捆绑在系统中,每次PepisCMS升级时都会升级,这些模块对所有PepisCMS应用程序可用。请参阅内置模块列表或检查模块源
  • 用户模块 - 用户空间模块,这些模块特定于您的应用程序实例。

默认情况下,所有模块都是禁用的,必须手动启用(安装)(在PepisCMS安装期间或任何后续点)。

模块安装

模块安装包括启用模块和配置其参数(如有)。具有管理界面的模块可以附加到管理面板菜单和/或仪表板。大多数模块都包含预定义的配置和展示默认值。配置选项和展示细节定义在模块描述符中(一个实现了ModuleDescriptableInterface接口的类)。

在模块安装/卸载时可以执行SQL代码。可以在模块描述符中指定包含SQL代码的文件。

要查看已安装的模块,请导航到开始 > 工具 > 已安装模块

浏览器中访问模块

管理模块操作

https:///admin/<modulename>/<action>

公共模块操作

https:///<modulename>/<action>

其中<modulename>是模块名称(目录名称),而<action>是方法名称(该方法必须有公共分类器)。

如果没有指定操作,则默认操作是index,即https:///<modulename>等于https:///<modulename>/index

请注意,必须安装模块,并且必须启用前端支持(页面和模块)才能访问公共控制器。这可以从开始 > 工具 > 网站配置中启用。

模块结构

  • 模块描述符(可选,当指定时必须实现ModuleDescriptableInterface
  • 管理控制器(可选)
  • 公共控制器(可选)
  • 管理视图(可选)
  • 公共视图(可选)
  • 模型(可选)
  • 库(可选)
  • 语言文件
  • 安全策略(security_policy.xml
  • 附加资源(如默认图标:<module_name>/resources/icon_16.png<module_name>/resources/icon_32.png

示例模块结构

以下是示例labels模块的结构

Module structure - new

还有一个遗留的模块结构布局。默认情况下不再支持遗留布局,但是可以从配置中启用它,如果您已经使用过去版本的PepisCMS生成了模块,并且不想升级

Module structure - legacy

内置模块

一个用于管理用户组和组访问权限的实用工具。

更多关于安全策略的信息。

Groups

用户账户

一个用于管理和注册新用户的实用工具。

User accounts

开发工具

Development tools

系统日志

可以使用高级日志实用工具跟踪所有用户操作和意外的应用程序行为。

PepisCMS提供了一个日志API和一个控制台用于分析系统日志。

每个日志都包含以下条目

  • 事件时间戳
  • 生成事件的用户ID/电子邮件
  • 创建条目的用户的IP地址
  • 模块名称(如有)
  • 收集名称 – 用于分组事件和绘制统计信息的抽象标签
  • 调试消息
  • 事件发生的URL
  • 事件严重性 – info,notice,warning,error

System logs

SQL控制台

SQL console

系统信息

显示系统信息、路径、版本、占用存储。

System information

翻译器

一个用于翻译用户界面的实用工具。

Translator

Symfony2桥梁

允许使Symfony缓存无效并查看Symfony日志。

Symfony2桥梁必须首先通过添加piotrpolak/codeigniter-symfony2-bridge库来启用。请参阅codeigniter-symfony2-bridge项目

备份

允许创建和下载MySQL SQL转储。

CRUD

此模块是任何其他CRUD模块的基础。它不可安装。

管理面板HTML自定义

允许将HTML片段注入管理面板的页眉和页脚。

配置值

允许编辑存储在数据库中的配置值。

生成CRUD模块

CRUD代表创建、读取、更新和删除。PepisCMS旨在简化为管理数据库表中存储的数据创建典型CRUD模块。

为给定的数据库表生成CRUD模块

  1. 对数据库执行SQL DDL。您可以使用捆绑的SQL控制台模块

  2. 确保已安装开发工具模块

  3. 导航到开始 > 工具 > 开发工具 > 创建新模块

  4. 提供必填的数据表名称和可选的模块详细信息

    Generating a CRUD module

    • 模块名称 - 留空以保留默认名称等于数据表名称
    • 是否解析数据库模式
    • 是否生成隐式安全策略
    • 模块类型(CRUD或默认/基本)
    • 数据库连接(如果您已配置多个数据库)
    • 用于生成翻译文件的编程语言
    • 是否生成公开控制器
  5. 继续

  6. 自定义翻译(可选)

  7. 自定义生成的控制器代码(可选)

  8. 上传自定义图标(可选)

您可以在sql/sample.sql中找到用于尝试的示例SQL文件。

内置工具

  • 网站的配置
  • 模块管理
  • 缓存管理/刷新
  • 重新加载(自己的)权限
  • 安全策略构建器
  • 检查自己的访问权限实用程序
  • 配置测试

安全策略

安全策略是一组要求用户权限,这些权限是访问控制器方法的必要条件。用户被授予上述定义的实体之一。

创建安全策略时,管理员首先定义所需的实体(如页面用户配置等)并将实体分配给控制器的方法。

访问检查是如何工作的

  1. 用户访问控制器方法
  2. 如果用户标记为root,则立即授予访问权限
  3. SecurityManager解析适当的security_policy.xml并读取给定控制器方法的实体和最小访问级别
  4. SecurityManager检查认证用户的组并计算关联的实体授予的访问映射
  5. SecurityManager检查计算的用户实体授予的访问映射是否包含与实体相关的条目
  6. SecurityManager将用户访问级别与所需的最小访问级别进行比较,如果满足条件或所需访问级别为NONE,则用户被授予访问控制器方法的权限。否则,用户被拒绝访问。

所有违反安全策略的行为都通过系统日志报告。

可能的访问级别

有四个访问级别

  • NONE
  • 读取
  • 写入
  • 全部

实体

实体只是一个表示核心业务对象的字符串。

示例:通过module控制器的不同方法实现管理、重新排列、管理和运行模块。每个方法为module实体具有不同的最小访问级别。

<?xml version="1.0" encoding="UTF-8"?>
<security_policy generated_at="2018-04-18 23:18:56" version="1.1">
  <policy module="system">
  
    <!-- ... -->
    
    <controller name="module">
      <method name="index">
        <entity name="module" access="READ"/>
      </method>
    </controller>
    <controller name="module">
      <method name="move">
        <entity name="module" access="WRITE"/>
      </method>
    </controller>
    <controller name="module">
      <method name="setup">
        <entity name="module" access="FULL_CONTROL"/>
      </method>
    </controller>
    <controller name="module">
      <method name="do_setup">
        <entity name="module" access="FULL_CONTROL"/>
      </method>
    </controller>
    <controller name="module">
      <method name="uninstall">
        <entity name="module" access="FULL_CONTROL"/>
      </method>
    </controller>
    <controller name="module">
      <method name="run">
        <entity name="module" access="READ"/>
      </method>
    </controller>
    
    <!-- ... -->
    
  </policy>
</security_policy>

安全策略管理控制台视图:Security policy

另请参阅组模块

控制器、方法和反射

为每个定义了安全策略的控制器方法都关联了一个实体以上的最小所需访问权限。

反射机制用于扫描控制器方法。

在运行时更改安全策略

可以在任何时间更改安全策略,而无需更改代码或重新编译任何内容。AdminControllers初始化SecurityManager,该管理器以对程序员或系统用户透明的方式处理安全。

安全策略序列化和缓存

安全策略被序列化到XML文件(security_policy.xml)中,该文件与平台无关,并且可以手动编辑。为了减少每次请求解析XML文件所需的时间,安全策略以处理和序列化的缓存格式存储在永久存储或直接在内存中。

安全策略类型

有两种类型的安全策略

用户组

当核心和模块都创建了安全策略后,管理员可以创建用户组。创建一个组的过程类似于构建安全策略 - 管理员为授予组中任何人的每个实体选择一个访问级别。

单个用户可以属于任意数量的用户组。这提供了高度的灵活性,因为您可以分别管理这些组。

部署配置

项目可以部署在几种配置中。以下选项将按从小到企业的顺序介绍。

小型网站(内容管理系统,Web)

框架仅作为核心安装,提供构建可以使用多个模板的网站的基本功能;有一个SEO友好的前端以及简单的管理面板,用于管理页面、菜单、文件和管理员。

数据库管理面板(内部应用程序)

在此选项中,框架充当基本数据库应用程序,可以从各种位置访问。

框架可以同时管理不同类型的多个数据库。没有公共前端。

示例:发票应用程序

门户/电子商务应用程序(内容管理系统,Web)

门户结合了小型网站和内部应用程序的功能。门户的一些页面是动态生成的;平台和访客之间可以有一定的交互(评论、用户登录、订单处理等)。此类应用程序的管理员有一些额外功能和专用模块可供使用。

所有组件,包括业务逻辑,都放置在同一台机器上。

优点:易于实现,成本低

缺点:任何故障都可能是致命的,可能存在可扩展性问题

示例:博客、在线商店。

架构概述

系统核心

核心实现了大多数基本功能,并且预计在一段时间内将保持稳定。核心利用了CodeIgniter框架,该框架提供了基本架构、输入安全性和数据库ActiveRecord访问方法。

特别是针对PepisCMS的核心,一些类被重载或重写(请参阅重写的核心库)。

PepisCMS区分了4种类型的控制器

  • 基本控制器(与CodeIgniter相同)
  • ModuleController - 公共模块控制器
  • AdminController - 用于核心管理面板,透明地处理安全检查
  • ModuleAdminController - 支持热插拔和一种可视化方式,其中原始AdminController充当主机,将所有可访问的资源(转换)映射到ModuleAdminController实例,而不在内存中重复它们

模块

模块实现了特定于业务的特性,这些特性不是通用的,因此不应为应用程序的所有实例分发。模块可以轻松地从项目转移到项目,并且不应创建依赖冲突。每个模块都可以在任何时候启用/禁用。

系统和用户模块的工作方式完全相同。如果安装了与现有系统模块同名的用户空间模块,系统模块将完全被忽略——您可以覆盖默认的用户和日志模块。

了解更多关于模块的信息。

模型-视图-控制器架构模式

该应用程序围绕模型-视图-控制器模式构建。

一个请求触发一个控制器(控制器)方法,该方法使用封装在模型(和库)中的逻辑来准备视图层的数据。

模型

模型使用数据访问对象模式封装数据访问。

模型提供读取、更新和删除实体的方法。CodeIgniter使用stdClass的实例来表示实体。

实体

  • 没有方法
  • 字段反映数据库结构(查询结果集结构)

所有模型必须以大写字母开头,并且必须后缀为_model。与库不同,模型实例的名称是区分大小写的(这来自CodeIgniter引擎)。

了解更多关于CodeIgniter模型的信息。

PepisCMS提供了一些基础模型,可以扩展以简化开发。

视图

视图用作表示层。它完全受控制器控制,但它也可以拉取由控制器初始化的模型或库提供的一些数据。在控制器内部准备所有数据,并将视图仅用作“显示层”,其中不包含任何逻辑——这样做可以大大简化视图的更改,例如从纯HTML更改为JavaScript使用的JSON格式。

要加载视图,应使用来自Enhanced_controller$this->display()方法。它将根据模块名称(如果有的话)、控制器名称和方法名称自动计算视图的路径。

要将变量分配给视图,应使用$this->assign('variable-name', 'variable-value')方法。

控制器

控制器是这些组件,它们解释输入、做出一些决策并准备输出数据。在Web应用程序的情况下,我们通过输入理解GET/POST变量、会话变量、Cookies以及几个其他方面。控制器实现了某些逻辑并从不同位置获取数据——数据库、Web服务、API、套接字等。

控制器利用它们加载的库和模型,它们不应直接操作数据库,而应通过使用模型。

PepisCMS区分4种类型的控制器

通用模型

Generic_model是一个扩展模型,实现了EntitableInterface接口,该接口由FormBuilder要求。

EntitableInterface接口指定了3个基本方法:saveById($id, $data)deleteById($id)getById($id)。您可以通过默认实现EntitableInterface类,但对于大多数情况,带有其辅助方法的Generic_model绰绰有余——在大多数情况下,应该仅扩展Generic_model

通用模型还实现了AdvancedDataFeedableInterface接口,这是DataGrid组件所需要的。

通用模型的方法值得关注,因为它们存在于PepisCMS使用的所有模型中。

有时不希望使用默认的通用模型方法,例如,当您需要获取最小数据集时。Generic_model默认情况下使用*通配符从数据库中选取所有内容。

FormBuilder库

一个可以基于提供的定义构建和处理HTML表单的库。表单构建器可以使用默认布局渲染表单,或者您可以注册一个额外的渲染器。表单构建器可以使用EntitableInterface的实例或绑定到任意数据库表的匿名Generic_model实例。

表单构建器的主要功能包括

  • 从定义生成HTML表单
  • 处理输入验证,包括服务器端(安全性)和客户端(JavaScript以提高响应性)
  • 处理数据库的读取/更新/插入
  • 可以通过模板进行自定义
  • 可以通过回调和自定义数据源对象扩展,这些对象实现了EntitableInterface
  • 可以处理数据库外键
  • 在使用表单构建器时,您可以通过两种方式指定表单的字段及其属性:通过API方法或通过定义。API方法是首先开发的,但不推荐在新项目中使用。从关联数组(多维哈希表)初始化表单定义使其更加灵活和可重用——当新属性实现时,之前定义的表单可以无缝工作。对程序员来说也更简单,因为定义中属性的顺序无关紧要。如果没有指定属性,则自动填充其默认值。
  • 用于生成表单构建器的定义与DataGrid使用的定义兼容,因此一个定义可以用于表单和表格。
  • 表单构建器紧密耦合于EntitableInterface - 它使用其saveById()getById()方法。

查看完整的FormBuilder API

生成表单

在最常见的场景中,可定制的通用模型作为表单构建器的数据源对象使用。场景如下

  1. 初始化表单构建器 $this->load->library('FormBuilder')
  2. 指定数据模型或使用提供表名的通用模型
  3. 指定实体ID的值 - $this->formbuilder->setId($id)
  4. 通过$this->formbuilder->setDefinition($definition)指定字段及其属性
  5. 指定返回链接 $this->formbuilder->setBackLink($link) - 用于“取消”按钮和表单保存后重定向用户的URL
  6. 触发表单填充/保存操作并生成结果HTML

生命周期回调

回调用于扩展或覆盖表单构建器执行的一些特定操作。

READ相关的回调应将对象作为参数,而WRITE回调应将数组作为参数。原因是行作为对象从数据库中检索,而表单值作为关联数组。

如果您不满意这种类型转换,可以通过类型转换确保特定的类型:$object = (object) $array,PHP 将完成所有魔法。

回调通常在控制器代码中以 "_" 为前缀的方法中定义,以防止通过 HTTP 访问。它们可以委派给外部类或可以是简单的函数,只要它们可以通过指定的参数调用。回调的概念与 ActionListener 的概念非常相似。请注意,如果您在控制器类中定义回调,则它必须是公共的,以便可以从外部实例调用它。

回调设置

$this->formbuilder->setCallback( array($this, '_fb_callback_before_render'), FormBuilder::CALLBACK_BEFORE_RENDER ); 
$this->formbuilder->setCallback( array($this, '_fb_callback_before_save'), FormBuilder::CALLBACK_BEFORE_SAVE ); 
$this->formbuilder->setCallback( array($this, '_fb_callback_after_save'), FormBuilder::CALLBACK_AFTER_SAVE ); 
$this->formbuilder->setCallback( array($this, '_fb_callback_on_save'), FormBuilder::CALLBACK_ON_SAVE ); 
$this->formbuilder->setCallback( array($this, '_fb_callback_on_save_failure'), FormBuilder::CALLBACK_ON_SAVE_FAILURE ); 
$this->formbuilder->setCallback( array($this, '_fb_callback_on_read'), FormBuilder::CALLBACK_ON_READ ); 
 
/** 
 * Called after validation, before saving 
 * @param array $data_array 
 */ 
public function _fb_callback_before_save( &$data_array ){} 
 
/** 
 * Some logs or statistics maybe? 
 * @param array $data_array  
 */ 
public function _fb_callback_after_save( &$data_array ){} 
 
/** 
 * Put here your rollback action 
 * @param object $object  
 */ 
public function _fb_callback_on_save_failure( &$object ){} 
 
/** 
 * Must overwrite the save procedure and return true or false 
 * @param object $object  
 */ 
public function _fb_callback_on_save( &$object ){} 
 
/** 
 * Must populate object 
 * @param object $object  
 */ 
public function _fb_callback_on_read( &$object ){} 
 
/** 
 * Can manipulate data after read, before rendering 
 * @param object $object  
 */ 
public function _fb_callback_before_render( &$object ){} 

图片字段回调

您可以给图片字段附加一个独立的回调。表单构建器一般回调与图片回调的区别在于,只有当上传新图片时才会调用图片回调,而每次保存表单时都会调用表单构建器回调。

示例回调(来自管理模块 CRUD 模板)

/**
 * Callback function changing the name of the file to SEO friendly
 *
 * @version: 1.2.3
 * @date: 2015-06-11
 *
 * @param $filename
 * @param $base_path
 * @param $data
 * @param $current_image_field_name
 * @return bool
 */
public function _fb_callback_make_filename_seo_friendly(&$filename, $base_path, &$data, $current_image_field_name)
{
    // List of the fields to be used, if no value is present for a given key
    // then the key will be ignored. By default all values of the keys
    // specified will be concatenated
    $title_field_names = array('name', 'title', 'label');

    $this->load->helper('string');
    $path = $base_path . $filename;
    $path_parts = pathinfo($path);

    // Attempt to build a name
    $new_base_filename = '';
    foreach ($title_field_names as $title_field_name) {
        // Concatenating all the elements
        if (isset($data[$title_field_name]) && $data[$title_field_name]) {
            $new_base_filename .= '-' . $data[$title_field_name];
        }
    }

    // Making it web safe
    if ($new_base_filename) {
        $new_base_filename = niceuri($new_base_filename);
    }

    // This should not be an else statement as niceuri can return empty string sometimes
    if (!$new_base_filename) {
        $new_base_filename = niceuri($path_parts['filename']);
    }

    // This should normally never happen, but who knows - this is bulletproof
    if (!$new_base_filename) {
        $new_base_filename = md5(time() + rand(1000, 9999));
    }

    $new_base_path = '';
//        $new_base_path = date('Y-m-d') . '/'; // Will create directory based on date
//        $new_base_path = $new_name_base . '/'; // Will create directory based on the niceuri value
//        @mkdir($base_path . $new_base_path); // Do not forget!
    // We don't like upper case extensions
    $extension = strtolower($path_parts['extension']);
    $new_name = $new_base_filename . '.' . $extension;

    // Protection against existing files
    $i = 2;
    while (file_exists($base_path . $new_base_path . $new_name)) {
        $new_name = $new_base_filename . '-' . $i . '.' . $extension;
        if ($i++ > 50 || strlen($i) > 2) // strlen is a protection against the infinity loop for md5 checksums
        {
            // This is ridiculous but who knowss
            $i = md5(time() + rand(1000, 9999));
        }
    }

    // No need to change filename? Then we are fine
    if ($filename == $new_name) {
        return TRUE;
    }

    // Finally here we go!
    if (rename($path, $base_path . $new_base_path . $new_name)) {
        $data[$current_image_field_name] = $new_base_path . $new_name;
        $filename = $new_base_path . $new_name;

        return TRUE;
    }
    return FALSE;
}

DataGrid 库

一个具有丰富数据视图网格的库,包括分页、排序和筛选。

特性

  • 使用网格定义以最小努力生成 HTML 视图
  • 允许对单个单元格应用回调格式化函数
  • 可以定义和应用筛选器
  • 支持数据集分页
  • 允许通过指定的列对数据集进行排序
  • 解析 OneToMany 和 ManyToMany 外键
  • 支持行操作(链接)
  • 支持行图标(缩略图)以及基于元组数据的额外行样式

DataGrid 筛选器

筛选器通过将 "where" 条件应用到查询中,以透明的方式限制数据集。

每个筛选器都可以有一个与之关联的 "filter_condition" 参数,该参数指定条件类型。只要筛选条件不同,就可以将多个筛选器与字段关联起来 – 例如,您可以通过同时使用 "date ge" 和 "date le" 来实现 "日期介于" 筛选器。

可能的筛选器类型

可能的筛选器条件

用法

DataGrid 定义是一个关联数组,最好使用 CrudDefinitionBuilder 构建。

完整

$this->load->library('DataGrid');
echo $this->datagrid->setFiltersShownBeforeGrid(TRUE)
    ->setFiltersShownAfterGrid(TRUE)
    ->setOrderable(TRUE)
    ->setTableHeadVisible(TRUE)
    ->setTitle("My Table")
    // All links will be generated with respect to this base URL
    ->setBaseUrl(admin_url() . 'somepage/edit')
    ->setDefaultOrder('id', 'asc')
    ->setItemsPerPage(300)
    ->setDefinition($definition) 
    ->addFilter('Since', 'published_since_datetime',DataGrid::FILTER_DATE, FALSE,
        DataGrid::FILTER_CONDITION_LESS_OR_EQUAL)
    ->addFilter('To', 'published_since_datetime', DataGrid::FILTER_DATE, FALSE,
        DataGrid::FILTER_CONDITION_GREATER_OR_EQUAL)
    ->setRowCssClassFormattingFunction(function ($line) {
        if ($line->is_active == 1) {
            return DataGrid::ROW_COLOR_GREEN;
        } else {
            return DataGrid::ROW_COLOR_RED;
        }
    })
    ->setFeedObject($this->MyFavourite_model)
    ->generate();

简约,具有隐式值

$this->load->library('DataGrid');
// All links will be generated with respect to this base URL
echo $this->datagrid->setBaseUrl(admin_url() . 'somepage/edit')
    ->setDefinition($definition)
    ->setTable('items') // Will automatically instantiate Generic_model for 'items' table
    ->generate();

查看完整的 DataGrid API

DataGrid 单元格值格式化回调

使用单元格值格式化回调,您可以在运行时修改单元格的值,例如添加字符串后缀、显示图片或插入链接。

回调必须是一个函数或返回字符串的公共方法,它接受两个参数:单元格内联值和表示行(行)值的对象。通常,回调方法是在控制器中定义的,并以前缀 "_"(下划线)开头,以防止通过 HTTP 访问。

public function _datagrid_format_order_value( $cell_value, &$line ) { 
    return $cell_value.' PLN'; 
}

CrudDefinitionBuilder

CrudDefinitionBuilder 使生成 DataGrid 和 FormBuilder 定义更容易、更安全(类型安全)。

以下是一些示例代码(请参阅 CrudDefinitionBuilder 代码 以获取完整参考)

$definition = CrudDefinitionBuilder::create()
    ->withField('address')
        ->withFilterType(DataGrid::FILTER_BASIC)
        ->withShowInGrid(FALSE)
        ->withShowInForm(TRUE)
        ->withInputType(FormBuilder::TEXTFIELD)
        ->addValidationRule('required')
        ->addValidationRule('valid_phone_number')
        ->addValidationRule('max_length[13]')
    ->end()
    ->withField('date')
        ->withShowInGrid(TRUE)
        ->withShowInForm(FALSE)
        ->withInputType(FormBuilder::TEXTFIELD)
    ->end()
        ->withField('date_sent')
        ->withShowInGrid(TRUE)
        ->withShowInForm(FALSE)
        ->withInputType(FormBuilder::TEXTFIELD)
    ->end()
    ->withField('body')
        ->withFilterType(DataGrid::FILTER_BASIC)
        ->withShowInGrid(TRUE)
        ->withShowInForm(TRUE)
        ->withInputType(FormBuilder::TEXTAREA)
        ->addValidationRule('required')
        ->addValidationRule('max_length[480]')
    ->end()
    ->withField('is_incoming')
        ->withFilterType(DataGrid::FILTER_SELECT)
        ->withValues(array(
            0 => $this->lang->line('global_dialog_no'),
            1 => $this->lang->line('global_dialog_yes')
        ))
        ->withFilterValues(array(
            0 => $this->lang->line('global_dialog_no'),
            1 => $this->lang->line('global_dialog_yes')
        ))
        ->withShowInGrid(TRUE)
        ->withShowInForm(FALSE)
        ->withInputType(FormBuilder::TEXTAREA)
        ->withNoValidationRules()
    ->end()
    ->withImplicitTranslations($module_name, $this->lang)
    ->build();

ContainerAware

ContainerAware 是一种从库和自定义类中无缝访问 CodeIgniter 容器服务的方式。

您只需要将您的类扩展为 ContainerAware,然后您就可以立即像从控制器或模型中访问它们一样访问所有服务。

使代码从

// The oldschool CodeIgniter way

class YourOldSchoolNastyLibrary
{
    public function myServiceMethod() {
        $CI = CI_Controller::getInstance(); // THAT IS NASTY
        $CI->load->library('email');

        // Autocomplete and method prediction does not work or requires additional hacks :(
        return $this->email->from('noreply@example.com')
                ->to('recipient@example.com')
                ->subject('Hello')
                ->body('Hello World!')
                ->sent();
    }
}

转换为方法体中不包含静态调用的代码

// The PepisCMS way

class YourNewNiceLibrary extends ContainerAware
{
    public function myServiceMethod() {
        $this->load->library('email');

        // Autocomplete and method prediction works out of the box :)
        return $this->email->from('noreply@example.com')
                ->to('recipient@example.com')
                ->subject('Hello')
                ->body('Hello World!')
                ->sent();
    }
}

如果您不能(或不想)扩展ContainerAware类,则可以自行实现自己的魔法方法 `__get()`,并重用由ContainerAware提供的静态辅助工具

class YourNewNiceAlternativeLibrary
{
    public function __get($var)
    {
        return ContainerAware::__doGet($var);
    }

    public function myServiceMethod() {
        $this->load->library('email');

        // Autocomplete and method prediction does not work out of the box :(
        return $this->email->from('noreply@example.com')
                ->to('recipient@example.com')
                ->subject('Hello')
                ->body('Hello World!')
                ->sent();
    }
}

简化领域模型

Simplified domain model

应用程序助手

以下是PepisCMS辅助工具列表

  • dialog_message 对话/ UI 相关函数。

    • display_error($message)
    • display_warning($message)
    • display_notification($message)
    • display_success($message)
    • display_tip($message)
    • display_breadcrumb($breadcrumb_array, $icon = false)
    • display_session_message() - 渲染并打印会话闪存消息。
    • get_warning_begin()
    • get_warning_end()
    • display_steps($steps, $type)
    • display_steps_circle($steps)
    • display_steps_dot($steps)
    • display_action_bar($actions)
    • button_generic($label, $url, $icon_path, $extra_classes = '', $id = false)
    • button_cancel($url = '#', $extra_classes = '', $id = false, $label = false)
    • button_back($url = '#', $extra_classes = '', $id = false, $label = false)
    • button_next($url = '#', $extra_classes = '', $id = false, $label = false)
    • button_previous($url = '#', $extra_classes = '', $id = false, $label = false)
    • button_apply($extra_classes = '', $id = false, $label = false)
    • button_save($extra_classes = '', $id = false, $label = false)
    • dashboard_box($name, $url, $icon_path = false, $description = false, $is_popup = false, $target = false)
    • display_confirmation_box($message, $explanation = '')
    • display_error_box($message, $explanation = '')
  • email_html 函数,简化了构建HTML系统邮件的过程。

    • email_html_open($padding = 20)
    • email_html_close()
    • email_h1_open()
    • email_h1_close()
    • email_h2_open()
    • email_h2_close()
    • email_p_open()
    • email_p_close()
    • email_a_open($url)
    • email_a_close()
    • email_html_footer_open($padding=0, $margin_top=40)
    • email_html_footer_close()
  • google_maps 获取给定地址坐标的函数。

    • google_maps_locate($address) - 返回表示给定地址坐标的数组(lat, lng)。
  • mysqldump 用于从MYSQL数据库创建备份的函数。

    • mysqldump($db_host, $database, $db_user, $db_password, $tables = false, $dump_to_filename = false, $dump_structure = true) - 将MySQL数据库导出到文件。
  • os 检测Windows系统的函数。

    • is_windows()
  • path 路径辅助函数。

    • module_path($module_name = false)
  • popup 弹出/ UI 相关函数。

    • popup_close_html() - 返回用于关闭弹出窗口的字符串。
  • youtube YouTube URL解析函数。

    • youtube_get_id_by_url($url) - 从YouTube视频URL中提取YouTube ID。

CodeIgniter辅助工具的定制或扩展

  • PEPISCMS_date 扩展了CodeIgniter日期辅助工具。

    • utc_timestamp() - 生成与MySQL UTC_TIMESTAMP函数兼容的时间戳值。
    • date_spectrum($today_time, $days_before = 30) - 从过去若干天生成到现在的日期频谱。
    • fill_date_spectrum_values($values, $today_time, $days_before = 30, $default_value = 0) - 接受值映射并确保没有日期间隔。
  • PEPISCMS_string 扩展了 CodeIgniter 字符串助手。

    • niceuri($name) - 生成一个可用于 URL slugs (URL id) 的 URL 友好字符串,支持西里尔字母。
    • shortname($name, $maxlength = 60, $separator = '...') - 生成一个缩短的字符串,在缩短值的中间插入 ...。
    • `remove_separators($str)' - 返回所有单词分隔符被移除的字符串(空格、破折号、减号、加号)。
  • PEPISCMS_url 扩展了 CodeIgniter URL 助手。

    • admin_url($is_absolute = true) - 返回管理员的基础 URL。
    • module_url($module_name = false) - 返回指定模块的相对管理员模块基础 URL。如果没有指定模块,则使用当前正在运行的模块。
    • module_resources_url($module_name = false) - 返回指定模块的相对公共资源 URL。如果没有指定模块,则使用当前正在运行的模块。
    • site_theme_url($theme_name = false) - 返回相对主题路径。如果没有指定主题,则使用系统配置的主题。
    • module_icon_small_url($module_name = false) - 返回管理员模块图标 URL。如果没有指定模块,则使用当前正在运行的模块。
    • current_url() - 返回当前请求的绝对 URL。

基准测试

PepisCMS 设计时考虑了小的内存占用和处理能力。

要启用分析器,请更改以下属性

// application/config.php

$config['enable_profiler'] = TRUE;

您可能会观察到,对于并发请求,会跳过访问检查和菜单渲染。

与CodeIgniter的变更比较

启用库和模型自动完成预测

自动完成和方法预测对于扩展以下类(所有 PepisCMS 控制器类型)、EnhancedControllerGeneric_modelContainerAware 的类默认开启。

这是通过在上面的类中添加 @property 注解来实现的。

手动生成项目标题

要重新生成库和模型定义并启用 CodeIgniter 在 PepisCMS 中的自动完成预测,您需要

  1. 安装 开发工具 模块并导航到模块仪表板 Autocomplete

  2. 生成 headers 文件,该操作将在 application/dev/_project_headers.php 下生成一个定义文件 _project_headers.php

  3. 将 CodeIgniter Controller.php 和 Model.php 标记为纯文本(右键单击 -> 标记为纯文本)。文件路径分别是 vendor/codeigniter/framework/system/core/Controller.phpvendor/codeigniter/framework/system/core/Model.php

  4. 享受自动完成预测和代码建议 :) Autocomplete

可选库

PHPExcel 用于 Excel 电子表格导入/导出

PHPSpreadsheet 桥接库默认不提供。要启用对 Excel 文件导入/导出的支持,请添加缺失的依赖项。一旦库存在于类映射中,Excel 的支持功能将自动启用。Excel 的支持可以在任何时候启用。

composer require phpoffice/phpspreadsheet 1.5.* --update-no-dev

PHPCas 用于 CAS 认证

PHPCas 桥接库默认不提供。要启用 CAS 支持,请在 PepisCMS 设置配置之前安装 PHPCas 库。

composer require jasig/phpcas 1.3.5 --update-no-dev

启用 Symfony 桥接

Symfony 桥接库默认不提供。Symfony 桥接可以在任何时候启用。

composer require piotrpolak/codeigniter-symfony2-bridge --update-no-dev

启用 Twig 支持

composer require twig/twig 1.* --update-no-dev

图标集

Farm Fresh Icons Pack https://fatcow.com/free-icons,许可协议为 Creative Commons Attribution 4.0 License