【问题标题】:Symfony 4: How to organize folder structure (namely, your business logic)Symfony 4:如何组织文件夹结构(即你的业务逻辑)
【发布时间】:2018-05-15 15:02:52
【问题描述】:

Symfony Best Practices中建议不要使用bundle来组织业务逻辑。

只有在其中的代码打算在其他应用程序中按原样重用时才应使用捆绑包:

但捆绑包是指可以重复使用的东西 一个独立的软件。如果 UserBundle 不能“按原样”使用 其他 Symfony 应用程序,那么它不应该是它自己的包。

所以,当我将我的应用程序从 Symfony 3.3 升级到 Symfony 4 时,我认为这是重新组织我的代码的正确时机。

目前我遵循“捆绑结构”:

- src
   - AppBundle
      - Controller
      - Entity
      - Repository
      - Resources
      - ...
   - MyNamespace
      - Bundle
          - BundleTodo
              - Controller
              - Entity
              - Repository
              - Resources
              - ...
          - BundleCatalog
              - Controller
              - Entity
              - Repository
              - Resources
              - ...
          - BundleCart
              - Controller
              - Entity
              - Repository
              - Resources
              - ...
          - ...

现在,有了新的目录结构,我应该如何组织我的代码?

我想这样组织它:

-src
   - Core
      - Controller
      - Entity
      - Repository
      - ..
   - Todos
      - Controller
      - Entity
      - Repository
      - ..
   - Catalog
      - Controller
      - Entity
      - Repository
      - ..
   - Cart
      - Controller
      - Entity
      - Repository
      - ...

但是,这是正确的吗? Symfony 4 和 Flex 的预期文件夹结构有什么问题吗?

或者像这样更好:

-src
   - Controller
       - Core
       - Todos
       - Catalog
       - Cart
       - ...
   - Entity
       - Core
       - Todos
       - Catalog
       - Cart
       - ...
   - Repository
       - Core
       - Todos
       - Catalog
       - Cart
       - ...
   - ...

这同样适用于project directory structure 中描述的其他根文件夹(关于如何覆盖它)。

在决定我的新文件夹结构时是否需要考虑任何规则或限制?

尝试解决问题

所以,为了解决这个问题,我会更深入地研究文档,我会在这里写下我会发现的。


【问题讨论】:

  • 没有正确的答案,这个问题如山之水。 Symfony 在某种程度上倾向于第二种方法,即开箱即用,控制器目录下的所有类都被视为控制器。同样,实体下的任何内容都可以视为实体。但是不要让框架支配你的应用程序设计。我更倾向于第一种方法,但一旦你深入了解细节,你可能会发现自己还有很多其他类型的类。
  • @Cerad,必须存在正确答案。正如您所指出的,Symfony 在某种程度上倾向于第二种方法,将controller 文件夹中的所有类视为控制器,entity 文件夹中的实体,等等。所以,这已经是使用第二种方法的好点了。问题比我描述的更深:有表单类型、序列化程序类和更多“东西”,如果放在一个文件夹而不是另一个文件夹中,它们就会获得特定的含义。
  • 确实框架不应该规定任何东西,但是如果我选择使用一个,我必须按照它告诉我的去做,而不是选择一个不同的框架或者干脆不使用它的“高级”功能(我想使用它们)......
  • 是的。如果每件事都只有一个正确的答案,那么生活会简单得多。问题是 Symfony 可以通过非常小的配置更改来支持多种方法。细节是让事情变得混乱的原因。正如您在评论中提到的,必须考虑表单、视图、业务逻辑等。我喜欢你的第一种方法,除了我经常有相关的“嵌套”功能而且我很少根据对象类型创建目录。 Symfony 很好地处理了这种方法。
  • “我很少根据对象类型创建目录”:这句话是什么意思?能给我举个例子吗?无论如何,我会更深入地研究文档,我正在寻找一些解决方案......我将更新我的问题......

标签: symfony symfony4


【解决方案1】:

正如 cmets 中所述,Symfony 可以很好地与所有这些结构一起工作,所以我们确实不能在这里有一个公认的答案,但这是我的两分钱。

说实话,最好的做法是独立于框架来组织架构(主要是因为这个原因,Symfony 4 不再强加捆绑包)。

但实际上,除了非常具体或复杂的项目外,拥有一个“面向symfony”的组织会更实用。

以下是我的个人偏好,也受到我项目类型的强烈影响(面向 CRUD,Rest API,没有强大的业务逻辑)

总的来说,我正在朝着这样的结构发展:

-src
   - Controller
       - Core
       - Todos
       - ...
   - Entity
       - Core
       - Todos
       - ...
   - Repository
       - Core
       - Todos
   - Validator (or other Symfony oriented components)
       - Core
       - Todos
   - Others (depend on project)
       - Core
       - Todos
   - ...

原因是:

  • 使用 autowire 减少服务定义 - 是的,我很懒 ;-)

    如果您需要将存储库或控制器注册为服务,您可以通过一个声明来完成。

  • 在 Symfony Flex 配方中,通常使用这种结构。

    例如,DoctrineBundle 初始化 src/Entitysrc/Repository 文件夹和包含实体的配方也使用此结构。

但请记住,Symfony Flex 不是强制性的。其目的主要是为了简化项目的初始化并使框架更容易被初学者使用

【讨论】:

  • 业界一致认为,基于特征的结构使开发人员需要更改的内容彼此接近。公认的结构将它们分开在类似名称的类的巨大堆中。因此,黄色引用完全不合时宜。
【解决方案2】:

康威定律:

设计系统...被限制生产的组织 设计是这些通信结构的副本 组织。

您应该围绕您组织工作的方式来设计您的目录结构。

如果您或您的同事在每个功能的基础上进行全栈工作,您应该按功能对代码进行分组。它将使导航和代码发现更容易。

如果您或您的同事在后端、前端、翻译等方面非常专业,您应该围绕这些来组织您的代码。基于每个功能的目录结构将支持明确的职责划分。

此外,深度应取决于您预计项目的规模。如果这将是 5 个人以上的 5 年以上的努力,那么您可能应该使用嵌套拆分每个功能和每个功能,如前所述,具体取决于工作组织。如果这将是一个人 3 个月的项目,即一些简单的内部工具,你可能应该使用更扁平的结构。我还建议坚持默认设置。

另外,我发现这篇文章内容丰富:https://blog.nikolaposa.in.rs/2017/01/16/on-structuring-php-projects/

【讨论】:

    【解决方案3】:

    2nd 结构非常适合复杂的应用程序,业务领域分裂。
    Symfony 4 很容易以这种方式配置其应用程序。

    ├─ assets/
    ├─ bin/
    │  └─ console
    ├─ config/
    │  ├─ doctrine/ 
    │  │    ├─ core/
    │  │    └─ sample/
    │  ├─ packages/
    │  ├─ routes/
    │  └─ validator/
    │  │    ├─ core/
    │  │    └─ sample/
    ├─ public/
    │  └─ index.php
    ├─ src/
    │  ├─ Core/         
    │  │  ├─ Controller/
    │  │  ├─ Entity/
    │  │  ├─ Repository/
    │  │  └─ ...
    │  ├─ Sample/      
    │  └─ ...
    ├─ templates/
    │  ├─ core/
    │  └─ sample/
    ├─ tests/
    ├─ translations/
    ├─ var/
    │  ├─ cache/
    │  ├─ log/
    │  └─ ...
    └─ vendor/
    

    只需一点配置:服务自动连接、自动配置等...就像一个魅力一样工作。

    # config/packages/doctrine.yaml
    doctrine:
        # ...
        orm:
            # ...
            auto_mapping: true
            mappings:
                App\Core:
                    is_bundle: false
                    type: yml
                    dir: '%kernel.project_dir%/config/doctrine/core'
                    prefix: 'App\Core\Entity'
                    alias: 'AppCore'
    
    
    #config/routes/annotations.yaml
    core_controllers:
        resource: ../../src/Core/Controller/
        type: annotation
    
    
    # config/services.yaml
    # But I prefer to put this on a separate config/services/_auto.yaml
    services:
        App\:
            resource: '../../src/*/*'
            exclude: '../../src/*/{Entity,Migrations,Tests,Kernel.php}'
    
        app_controller:
            namespace: App\
            resource: '../../src/*/Controller'
            tags: ['controller.service_arguments']
    

    【讨论】:

    • 哦,是的,当然:但是哪个“一点点配置”是棘手的部分!如果没有要配置的特定配置(请原谅我开玩笑的话)这个答案是没有用的!
    • @Aerendir 你是对的,我添加了缺少的配置。我的提议不是小型应用程序的最佳选择,但我发现它适合组织大型应用程序。
    • 我认为这是能够复制代码的最佳方式。 j-guyon 放的那个不是那么可复制,因为您必须导航更多目录并从一个项目复制到另一个项目更加复杂。非常感谢您的出色回答。
    猜你喜欢
    • 1970-01-01
    • 2018-06-06
    • 1970-01-01
    • 2012-02-09
    • 1970-01-01
    • 2016-09-09
    • 1970-01-01
    • 1970-01-01
    • 2019-12-25
    相关资源
    最近更新 更多