Initial Data in Laravel Projects

Initial data for a project, such as roles (e.g., super admin role), permissions, and which users are granted admin privileges, is typically designed during the requirements analysis phase.

This initial data is a part of the project’s operation and will be used in the production environment. However, data seeding is generally used during the development phase.

Although Laravel doesn’t offer a built-in solution for this, we can leverage the database migration feature to achieve it. In terms of functionality, data migration is also part of the project, with the execution timing aligning perfectly with the installation of the project. The execution order is critical, ensuring that the initialization data is applied after the database table structure is created.

We can generate migration files for initializing data using the following command:

php artisan make:migration seed_categories_data

We define the naming convention for such migration files as seed_(table_name)_data.

For project initialization data, using a Seeder is less convenient than using a database migration file, especially in collaborative development. With multiple migration files from different developers, you only need to execute a single migration command. If issues arise, you can easily roll back, whereas Seeders lack rollback functionality. Rollback is crucial, both in development and production environments. If the initial data can be fully determined before the project is deployed (which is almost impossible), then using a Seeder is acceptable and recommended. However, after the project goes live, it’s likely that the initial data will require modifications (such as additions, deletions, or updates). In such cases, using a Seeder is inappropriate, and database migration files should be used instead. Seeders are primarily used for generating test data, and they should not be used for altering or deleting production data.

Laravel项目的初始化数据

项目的初始化数据,例如一个应用程序有哪些角色(例如超级管理员角色)、哪些权限、授予哪些用户管理员权限是在需求分析阶段就设计好的。

项目的初始化数据是项目运行的一部分,在生产环境下也会使用到,而数据填充(Seeder)一般在开发时使用。

虽然Laravel没有自带此类解决方案,不过我们可以借助数据迁移功能来实现。在功能定位上,数据迁移也是项目的一部分,执行的时机刚好是在项目安装时。并且区分执行先后顺序,这确保了初始化数据发生在数据表结构创建完成后。

我们可以使用命令生成数据迁移文件,作为初始化数据的迁移文件:

php artisan make:migration seed_categories_data

我们定义这种迁移文件的命名规范为seed_(数据库表名称)_data

对于项目的初始化数据,使用Seeder没有使用数据库迁移文件来得方便,特别是在多人协作开发时,对于别的开发者提供的多个数据库迁移文件,你只需执行一条迁移命令即可,如果有问题还能回滚,Seeder没有回滚功能。回滚功能无论是对于开发环境还是生产环境都是很重要的。 如果项目的初始化数据在项目上线(部署到生产环境)之前,就能全部确定下来(这几乎不可能),那么使用Seeder是可以的,也是应该的。但是在项目上线之后,很可能还要对初始化数据进行增删改操作,此时再使用Seeder是不合适的,应该使用数据库迁移文件。Seeder主要用来生成测试数据,很难、也不要用Seeder来删改数据库数据。

Web应用的类型以及它们各自的理想实现/交付方式

本文翻译自Jason Miller的博客文章Application Holotypes

分析现实世界中的应用程序的特征很困难。我们经常看到有人对应用程序做出概括,既有漫不经心的,也有经过数据统计的:“单页应用程序比多页应用程序慢”或“TTI 低的应用程序加载速度更快”。然而,这些概括对于我们关心的应用程序的性能和架构特征都不太准确。我认为主要决定因素之一是产品的功能和设计约束,根据应用程序的功能和约束对其进行分类可以为每个应用程序面临的问题提供更有针对性和更有效的解决方案。

构建一组类别,以便有效地将应用程序分组是一种挑战:很难预测所有可能的组,每个组设定的边界都是主观的,可能会随着时间的推移而改变。此外,像这样的抽象分组可能很难推理或可视化。例如,我们可以向“胖客户端、以页面为中心的富媒体应用程序,具有离线浏览和用户生成内容的功能”的开发人员推荐哪些性能优化技术?如果转而问的是我们可以向“类似Instagram的应用程序”的开发人员推荐什么,这种讨论就更具体化、更容易进行了。

为了建立这种讨论框架,我们可以构建一个典型应用程序列表。这些应用程序既可以代表当今的网络,也可以基于我们预见到的开发人员为响应未来趋势和平台计划而做出的改变。为了方便起见,代表Web的长尾历史和遗留内容的部分典型应用程序更加通用,而代表当前和即将推出的部分典型应用程序可以更狭窄地限定讨论范围,以便提供更具体的建议。

每个典型应用程序都附有粗略的类别名称、额外的真实案例以及定义其架构的特征和约束。我还根据其架构提供了理想的部署实施和交付技术。

社交网络应用

  • 典型:Facebook
  • 其他案例:LinkedIn、Reddit、Google+
  • 特点:多面性、子应用程序、无限滚动内容、用户生成内容、实时更新、通知
  • 限制:过深的会话深度、大规模、实时更新、嵌入式内容的资源争用、嵌套应用程序、SEO
  • 理想实现方式:具有外壳和登录页面预渲染的单页应用程序。
  • 理想交付方式:独立显示模式下的 PWA。或TWA。

社交媒体应用

  • 典型:Instagram
  • 其他案例:Youtube、Twitter
  • 特点:富媒体、无限滚动内容、用户生成内容、实时更新、通知、可嵌入性、嵌入式内容
  • 限制:扩展会话深度、实时更新、嵌入式内容的资源争用、不间断媒体播放、SEO
  • 理想实现方式:具有应用程序外壳预渲染和缓存的单页应用程序。
  • 理想交付方式:独立显示模式下的 PWA。

店面应用

  • 典型:亚马逊
  • 其他案例:百思买、新蛋、Shopify(基于商店)
  • 特点:搜索、支付、可发现性、过滤和排序 限制:浅到中等会话深度、小交互、高购物车/结帐流失率、SEO
  • 理想实现方式:具有 CSR/SPA 接管或 turbolinks 样式转换的服务器呈现站点。
  • 理想交付方式:默认显示模式下的 PWA。

内容网站

  • 典型:CNN
  • 其他案例:FT、BBC、BuzzFeed、Engadget、Salon、Smashing Magazine、The Onion
  • 特点:可发现性、富媒体、嵌入式内容 限制:浅会话深度(~1)、广告和多变量测试的资源争用、SEO
  • 理想实现方式:具有轮播图风格过渡效果的服务器端渲染网站。
  • 理想交付方式:默认显示模式下的 PWA。

PIM应用

  • 典型:Gmail
  • 其他案例:Google 日历、Outlook.com、Fastmail
  • 特点:胖客户端、无限列表、嵌入式内容、富文本编辑、清理、MDI、存储、离线和同步、通知
  • 限制:延长会话长度、敏感且大量不可缓存的数据、高安全风险、经常离线
  • 理想实现方式:具有应用程序外壳缓存的单页应用程序。
  • 理想交付方式:独立显示模式下的 PWA。

生产力工具

  • 典型:Google Docs
  • 其他案例:Office.com、Zoho、Dropbox、Box
  • 特点:胖客户端、富文本编辑、离线和同步、文件系统、剪贴板、存储、图像处理、嵌入式内容
  • 限制:延长会话长度和多个并发会话有利于客户端实现。
  • 理想实现方式:单页应用程序。考虑应用程序前端缓存。
  • 理想交付方式:独立显示模式下的 PWA。

媒体播放器

  • 典型:Spotify
  • 其他案例:Youtube Music、Google Play Music、Tidal、Soundcloud、Pandora、Deezer
  • 特点:富媒体、胖客户端、无限滚动内容、过滤和排序、通知、操作系统集成、离线、可嵌入性
  • 限制:延长会话长度,用户浏览其他页面时必须继续播放。
  • 理想实现方式:具有应用程序前端预渲染和缓存的单页应用程序。服务器渲染 <head> 以SEO友好。
  • 理想交付方式:独立显示模式下的 PWA。

图形编辑器

  • 典型:Figma
  • 其他案例:AutoCAD、Tinkercad、Photopea、Polarr
  • 特点:3D 渲染和 GPU、图像处理、全屏和指针捕获、MDI、存储、离线、文件系统、线程、wasm
  • 限制:会话长度长、对输入和渲染延迟的敏感性、大对象/文件
  • 理想实现方式:单页应用。将更轻量的浏览 UI 与编辑器分开。
  • 理想交付方式:独立显示模式下的 PWA。

媒体编辑器

  • 典型:Soundtrap
  • 其他案例:Looplabs
  • 特点:音频处理、设备集成(midi、usb)、存储、离线、文件系统、线程、wasm
  • 限制:长会话长度、低延迟 DSP、低延迟媒体录制和播放、大文件大小/IO
  • 理想实现方式:单页应用。将更轻量的浏览 UI 与编辑器分开。
  • 理想交付方式:独立显示模式下的 PWA。

工程工具

  • 典型:Codesandbox
  • 其他案例:Codepen、Jupyter Notebook、RStudio、StackBlitz
  • 特点:胖客户端、MDI、存储、离线、文件系统、线程、嵌入式内容
  • 限制:极长的会话长度、低延迟文本输入、大内存占用、自定义输入处理和文本渲染、预览内容的安全性
  • 理想实现方式:单页应用。考虑将浏览 UI 与编辑器分开。
  • 理想交付方式:独立显示模式下的 PWA。

沉浸式/AAA游戏

  • 典型:Stadia
  • 其他案例:Heraclos、Duelyst、OUIGO 特点:3D 渲染和 GPU、P2P、音频处理、全屏和指针捕获、存储、离线、文件系统、线程、设备集成(游戏手柄)、wasm
  • 限制:会话长度长(高度交互)、沉浸感、对输入和渲染延迟极其敏感、需要一致或分步的 FPS、极端的资产大小
  • 理想实现方式:单页应用
  • 理想交付:全屏显示模式下的 PWA。

休闲游戏

  • 典型:Robostorm
  • 其他案例:Tank Off、War Brokers、GoreScript、Air Wars、”.io games”
  • 特点:2D 和 3D 渲染和 GPU、P2P、音频处理、存储、离线、可嵌入性
  • 限制:会话长度长、对输入和渲染延迟敏感、需要一致/分步 FPS
  • 理想实现方式:单页应用
  • 理想交付方式:嵌入另一个站点,或全屏显示模式下的 PWA。

托管钱包和非托管钱包

钱包按是否被托管可以分为:

  • 非托管钱包(non-custodial wallets)(也称为自托管钱包),意味着用户始终可以控制自己的私钥和资金。非托管钱包有trust、MetaMask、Coinbase等。
  • 托管钱包(custodial wallets),意味着用户的私钥和资金都放在钱包软件公司的服务器里。托管钱包有Binance Wallet等。

托管钱包就像将你的贵重物品存放在仓库中,而非托管钱包就像将它们存放在家中的保险箱中。因此,托管钱包需要较少的个人责任,但受第三方支配,而非托管钱包由你自己完全控制,但也意味着你承担全部责任,确保你的物品安全并保管你的密码和密钥。

SSG就是页面静态化技术

静态站点生成 (Static-Site Generation,缩写为 SSG),也被称为预渲染,是另一种流行的构建快速网站的技术。如果用服务端渲染一个页面所需的数据对每个用户来说都是相同的,那么我们可以只渲染一次,提前在构建过程中完成,而不是每次请求进来都重新渲染页面。预渲染的页面生成后作为静态 HTML 文件被服务器托管。

SSG就是页面静态化技术,是门户网站、WordPress博客常用的Web优化手段之一。

SSR类似于PHP程序,每有一个HTTP请求到来就会被运行一次,渲染输出HTML字符串给前端。如果网站的内容没有实时性,我们可以把渲染输出的HTML字符串缓存一段时间,当有HTTP请求到来时,直接返回缓存给前端,而不是实时渲染输出。这就是页面静态化技术的核心思想。

参考

服务端渲染 (SSR)

Does Stopping a Docker Container Equate to Shutting Down a VirtualBox VM?

To clarify, stopping a running Docker container is not the same as pausing it. Stopping a container terminates the processes inside the container and releases associated resources (like CPU and memory), but the container’s filesystem and state remain intact, similar to how VirtualBox retains hard disk data after shutting down a VM. The container’s data stays unless explicitly deleted (using rm).

The Difference Between Stop and Pause:

  • Stop: Completely terminates all processes inside the container, similar to turning off the power. When the container is restarted, it begins from its configured entry process.
  • Pause: Freezes all processes inside the container, keeping their state intact, but without releasing resources. A paused container can be resumed, much like the Suspend feature in VirtualBox.

停止(注意不是暂停)运行docker容器是不是相当于VirtualBox的虚拟机关机?

具体来说,停止运行中的 Docker 容器会终止容器内部的进程,释放相关的资源(如 CPU 和内存),但容器的文件系统和状态会被保留,就像 VirtualBox 虚拟机关机后硬盘数据依然保存一样,除非进行删除(rm)操作。

停止和暂停的区别在于:

  • 停止(stop):完全终止容器内的进程,相当于电源关闭,容器在下次启动后会重新开始其配置的入口进程。
  • 暂停(pause):冻结容器内的所有进程,进程状态保持,但并不释放资源,暂停的容器可以恢复继续运行,类似于 VirtualBox 的暂停(Suspend)功能。

Methods for Website Internationalization (Providing Multi-language Content)

For websites that use server-side templating engines (e.g., Laravel’s Blade) to render HTML documents, the approach to localization (internationalization) is as follows: For common pages like login and registration, you can use the __() function to translate text based on the lang= query parameter passed from the frontend. For other pages, the language-specific views should be placed in directories like resources/views/{language_code} (for Laravel) or public/{language_code} (where “public” refers to the web root directory).

For fully decoupled applications, such as those where the frontend is developed using MVVM frameworks like Vue.js or React.js for SPAs, and the backend is built with Laravel to provide APIs, localization methods differ. In this case, you should add language-specific subdomains at the domain level, such as cn.vuejs.org for the Chinese Vue.js site, ja.vuejs.org for the Japanese site, with the default vuejs.org serving the English version. Additionally, the database should support language-specific partitioning, where each language code has its own set of tables or databases.

网站国际化(提供多国语言内容)的方法

对于前端使用服务器端模板引擎(例如Laravel的blade)渲染输出HTML文档的开发方式,本地化(国际化)的方法是,通用的页面,例如登陆注册,可以使用__()函数根据前端传过来的lang=语言代码查询参数翻译文本。其他不同用的页面应该放在resources/views/语言代码目录(对于Laravel)或public/语言代码目录(public代表web根目录)下。

对于前后端完全分离的应用程序,例如前端使用Vue.js、React.js等MVVM框架开发SPA,服务器端使用Laravel开发并提供API给前端调用,本地化(国际化)的方法是,在域名层面添加语言代码子域,例如cn.vuejs.org、ja.vuejs.org分别显示中文Vue.js官网和日文Vue.js官网,主站vuejs.org默认英文Vue.js官网。 数据库也应该根据语言代码分库分表。

Laravel’s DB Facade Doesn’t Trigger Eloquent ORM Model Events

When using the DB facade to perform database operations in Laravel, Eloquent ORM model events like saving, saved, etc., are not triggered.

If you want to avoid triggering model events in event listeners or queued tasks, aside from using Eloquent’s saveQuietly, deleteQuietly, and similar methods, you can directly use the DB facade to execute database operations.

This approach allows you to bypass Eloquent’s event handling when necessary.