What’s the difference between a Block Class and a View Model in Magento?
It's difficult to know differences between a Block Class and a View Model in Magento 2. Let's find out what each of them does, and when to use one over the other.
In Magento, developers will come across two core components - Block Classes and View Models. But it’s difficult to understand the differences in design between these components.
Block Classes have been around since the early days of Magento. They handle a wide range of functionalities, from data logic to layout rendering. View Models, on the other hand, arrived more recently in Magento 2.2. They have a streamlined focus - just supplying data to the templates.
This distinction affects how and when each should be used. Block Classes provide flexibility for complex scenarios, but can be overkill for most scenarios. View Models promote clean code, yet lack some of the more advanced capabilities present in Block Classes.
So, which one should you choose for your next Magento project? The answer is... it depends!
Let’s go through the features, use cases, and recommended guidelines for when to use each. While View Models are preferred for new development, Block Classes still have merit in certain situations. Understanding the strengths and weaknesses of each will help you pick the correct component for your code.
What is a Block Class?
In Magento, a Block Class is a PHP class that extends
Magento\Framework\View\Element\ Template. It serves as an intermediary between the data source (like a database or API) and the presentation layer (templates).
The key responsibilities of a Block Class are:
- Fetching raw data from the source
- Processing and preparing the data for presentation
- Exposing methods for the templates to retrieve the prepared data
- Handling rendering logic for the templates
For example, the Product Detail page needs to show information about a specific product. The Block Class would retrieve the product data from the database, perform any formatting or transformations needed, and make methods like
getFormattedPrice() available to the template.
The template would then call these Block Class methods to access the data and render it correctly on the frontend. Block Classes also have access to layout XML, events dispatched with the layout, the template to be rendered, as well as parent & child blocks.
In summary, Block Classes handle both the logic to prepare data as well as some rendering-related tasks. They act as the bridge connecting data to presentation. But they also have some extra capabilities to modify the layout and rendering of the view.
What is a View Model?
A View Model in Magento is a PHP class that implements
View Models were introduced in Magento 2.2 to promote modular, testable code by separating responsibilities.
The sole focus of a View Model is to:
- Fetch data from repositories and interfaces
- Prepare and expose that data for templates
Unlike Block Classes, View Models are restricted to data handling responsibilities only. They do not perform any rendering or interact with the layout system.
For example, a Product View Model would retrieve the product entity using repositories, process and format it, and make data like
getDescription() available to templates.
The presentation and actual rendering would be handled in template files. View Models act as a bridge, providing templates with ready-to-use data. Multiple View Models could also be used within a single template, which provides some additional flexibility.
To summarize, View Models specialize in data management and preparation. They hand-off rendering tasks completely to templates for clear separation of concerns.
Key Differences and Use-Cases
Interacting with Layout XML
Interacting with layout XML is an area where Block Classes have exclusive capabilities that View Models lack.
Some examples of layout XML interactions only feasible via Block Classes:
- Dynamically modifying layout XML at runtime by adding, removing or setting blocks based on conditions.
- Using layout XML methods like
getGroupChildNames()etc. to generate and manage block hierarchy programmatically.
- Accessing customizable layout XML properties dynamically like
loadLayoutUpdates()to incorporate new layout handles based on backend configuration or code logic.
- Leveraging layout events like
layout_generate_blocks_afterto modify layout structure after initial generation.
generateXml()to programmatically generate fresh layout XML content.
View Models have no direct interface with the layout XML system. All interaction and modification logic needs to reside in Block Classes.
This makes Block Classes the right choice when layout manipulations are required at runtime based on custom logic or backend configurations. For simply fetching and supplying data, View Models would be suitable. But any level of dynamic layout management requires Block Classes.
Accessing Parent and Child Blocks
Another key difference is that Block Classes can access parent and child blocks, whereas View Models cannot.
Some examples of parent/child block interactions accessible only via Block Classes:
getParentBlock()to access the parent block instance and its methods, properties, etc.
getChildChildHtml($alias)to render and incorporate content from a child block into the parent output.
unsetChild()to dynamically manage child block hierarchy at runtime.
- Looping through child blocks using
getChildBlock($alias)for conditional logic.
getGroupChildNames($group)to retrieve child blocks registered to a specific group.
getLayout()->createBlock()to generate new child blocks on the fly based on logic.
View Models have no awareness of either their parent block or any child blocks. They cannot access or manipulate the block hierarchy.
This makes Block Classes necessary for scenarios like:
- Conditionally rendering a child block based on business logic
- Integrating child block content into parent using
- Dynamically managing child blocks of a parent block
Parent/child block interactions are intrinsic to Block Classes in Magento.
Complex Business Logic
For business logic that involves multiple operations, dependencies, and components, Block Classes tend to be better suited than View Models.
Some examples of complex logic that fits more naturally in Block Classes:
- Dependency injection involving many different services and helpers to carry out elaborate operations.
- Orchestrating data from multiple sources like APIs, repositories, session data to calculate or produce desired end result.
- Manipulating collections by applying filters, sorts, custom queries spanning multiple tables, etc. based on runtime values.
- Integration with many different types of objects like events, observers, model factories, etc. besides just templates.
- Stateful multi-stage operations involving temporary data storage, sessions, etc. to achieve overall outcome.
- Runtime caching of processed data or fragments to optimize performance, avoid repetitions.
- Assembling multiple templates and view elements in order to render final output.
View Models excel at singular data retrieval and preparation tasks. But Block Classes are better equipped to handle the orchestration of bringing together and directing different components to execute complex workflows. The flexibility and versatility of Block Classes make them more naturally capable of managing elaborate logic spanning multiple domains.
Sorting and Manipulating Collections
When it comes to sorting, filtering, and manipulating collection data, Block Classes tend to be better suited compared to View Models.
Some examples of collection handling that fits more naturally in Block Classes:
- Applying multiple sort orders dynamically based on runtime values from different sources.
- Filtering and querying across multiple tables using join statements to build custom product collections.
- Running collection operations like filtering, slicing, sharding based on configurations or real-time calculations.
- Integrating faceted navigation, layered filtering, and other complex collection transformations.
- Caching filtered or sorted collections for performance gains when logic needs to be reused.
- Performing batch updates on collections by integrating with model factories or repositories.
- Iterative collection loading and processing for large sets that need pagination or deferred loading.
View Models can technically perform all of these operations. However, encapsulating elaborate collection logic in View Models can significantly bloat them and make them difficult to maintain.
Block Classes do not impose any such restrictions, and allow collection manipulation code to reside naturally alongside the rest of the required business logic.
There are some render-related methods that are only available in Block Classes and not accessible in View Models.
Some examples of rendering logic that can only reside in Block Classes:
|toHtml(), _toHtml()||Override to customize rendering logic|
|getParentBlock(), getChildHtml()||Render child block content|
|getIsCacheable(), getCacheKeyInfo()||Fragment caching|
|getCssClass(), getClass()||Add dynamic CSS classes|
|getUrl()||Generate URLs for templates|
|getLoadCacheKey()||Customize cache keys|
|block_html_before/after||Inject logic pre/post render|
|getJsLayout()||Access/modify JS layout|
|_prepareLayout()||Insert dynamic content|
Since View Models are restricted from handling rendering, these methods are unavailable to them. Any logic that needs to tap into the rendering pipeline has to reside in a Block Class implementation. For purely preparing data separately, View Models suffice. But interfacing with rendering requires Block Classes.
Comparing Block Classes with View Models
Here are the key features of Block Classes and View Models, and the differences and use cases between them:
|Feature||Block Classes||View Models|
|Scope||Wide range of functionality - data logic, layout rendering, complex workflows||Focused only on data retrieval and preparation|
|Key Responsibilities||Data fetching, preparation, caching, rendering logic, layout XML, parent/child blocks||Just data fetching and preparation|
|Design Principles||Flexibility and power||Simplicity, single responsibility, separation of concerns|
|Use Cases||Complex transformations, dynamic layout, cross-component logic, legacy systems||Simple data tasks, decoupled logic, improved testability|
|Layout XML||Can interact and modify||No direct interface|
|Parent/Child Blocks||Can access relationships||Unaware of block hierarchy|
|Business Logic||Excellent for complex orchestration||Better for isolation over orchestration|
|Collections||Suited for advanced manipulation||Can clutter view models|
|Rendering||Can customize rendering pipeline||No access to rendering methods|
|Testability||Brittle due to multiple responsibilities||Improved testability in isolation|
|When to Use||Legacy systems, complex integrations, rendering needs||Simplicity desired, narrow scope|
The table highlights how Block Classes have a much wider scope and set of responsibilities when compared to View Models. Block Classes handle everything from data fetching to layout rendering and complex orchestration logic. In contrast, View Models have a narrow focus solely on retrieving and preparing data for templates.
In terms of design, Block Classes provide more flexibility and power but can get cluttered, while View Models aim for simplicity and separation of concerns. Some key differences are that Block Classes can interact with layout XML, access parent/child block relationships, handle complex business logic, perform advanced collection manipulation, and interface with rendering methods. View Models have none of these capabilities.
The constrained responsibilities of View Models make them better suited for scenarios where simplicity is desired and business logic has a narrow scope. Their isolation also promotes improved test coverage.
Takeaway: When To Use Each
Deciding between Block Classes and View Models requires carefully weighing their respective strengths and weaknesses within the context of your specific needs. There is no universal "one size fits all" rule. However, some guidelines can help point you in the right direction.
For new development, View Models should be the default choice. Their promotion of modular, focused code aligns well with modern best practices. However, some scenarios necessitate the flexibility of Block Classes, so avoid dogma if they better serve your needs. If both options work, lean towards View Models for improved testability.
When integrating with legacy systems built on Block Classes, continuing to use them may be more pragmatic than forcing an abrupt switch to View Models. The technical debt incurred may not be worth the theoretical benefits.
Pay close attention to the complexity of logic and orchestration required. View Models shine when business logic can remain narrowly scoped. Block Classes are better equipped for elaborate orchestration between diverse components. Resist bloating View Models with complex integrations better handled in Block Classes.
Consider your specific rendering needs. Customizations to layout XML, parent/child blocks, fragment caching, and other rendering concerns mandate Block Classes. Don't contort View Models to achieve such functionality when Block Classes were purpose-built for it.
While View Models promote separation of concerns, take care that separation doesn't turn into isolation. Some business logic intertwines closely with the templating environment. In these cases, the closer coupling of Block Classes may justify itself.
The end goal is maintainable, extensible code. This is achieved through transparent components with focused responsibility and minimal unnecessary coupling. Remember to let this drive your decision more than the credo to always use one choice over another.
Pragmatism and your specific needs should guide you to the right tool for each task. Both Block Classes and View Models have their place in creating powerful, future-proof Magento solutions.
Now that you know the difference between a Block Class and a View Model, you can start using them in your Magento projects. If you want to learn more about Magento 2, check out my Magento 2 Coding Kickstart course.
If any of the other terminologies were confusing, you may want to check out these other resources which may help you out: