I was thinking through some DAO design stuff with a teammate and came across an interesting question about which I have yet to find any best practices guidelines.
When creating a DAO object, when should the DB connection occur? We've talked through instantiating an object that creates a DB connection in a constructor (then uses it in subsequent methods) and making a static class that establishes a connection and tears it down after every method call.
Both have clear performance implications based on environment - a static object would be good for a few intermittent calls whereas instantiating an object that holds a connection would be great for a number of calls in a short amount of time for a small number of users.
Is there another way to do this? Perhaps something that would be better for performance across most situations?
Since you have tagged this as mvc, I will assume that your DAOs already exist within the model layer. As i understand it. the DAOs are responsible for for same task as Data Mappers, and provide the information from storage (which might or might not be SQL database) to your Domain Objects within the Model Layer.
The best way to deal with this issue would be to have factory, which create the data access objects within your model layer. This would have several advantages:
decoupling from the class names of different DAOs
ability to know when first DAO is initialized
sharing single DB connection between all DAO instances
This is how I would implement something like it:
class DaoFactory
{
protected $connection = null;
protected $provider = null;
public function __construct( $provider )
{
$this->provider = $provider;
}
public function create( $name )
{
if ( $connection === null )
{
$connection = call_user_func( $this->provider );
}
$instance = new $name;
$instance->setConnection( $connection );
return $instance
}
}
And the usage would look something like this:
$connectionProvider = function()
{
$instance = new \PDO('mysql:host=localhost;dbname=testdb;charset=utf8',
'username', 'password');
$instance->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
$instance->setAttribute(\PDO::ATTR_EMULATE_PREPARES, false);
return $instance;
};
$daoFactory = new DaoFactory( $connectionProvider );
Then you pass the $daoFactory variable to whichever object will require to create DAO. This way, if need arises, you can easily replace the factory (as long as it implements same create() method footprint), with something completely different. And your domain business logic is in no way impacted by such a change.
The objects which use this factory became completely unaware that there even exists a database connection, and that DAOs need it to function. And you can even end up with situations, when you don't even need to establish a connection to database.
Rant Since you have data access objects on your codebase, it would indicate that you are trying to use OOP. Or at least something similar. But the static classes/functions/variables are not part of OOP paradigm. If you have a class with static-only methods and few static variables, what you have actually made are just simple php function with global variables, wrapped in a namespace, which just happens to look like class.
PHP community tends to call this COP (class oriented programming) as a joke, but essentially it is procedural code.
Related
I do not understand why or when to use the resources in Laravel https://laravel.com/docs/7.x/eloquent-resources .
See this controller :
public function show(School $school)
{
// return response()->json($school, 200);
return new SchoolResource($school);
}
The both return solutions returned this kind of response :
{
"data": {
"id": "4f390a7b-3c3f-4c23-9e6a-dd4429cf835d",
"name": "school name",
.......,
The data are the results of a query automatically injected (here : $school).
And same question for a collection of resources. Imagine this controller :
public function index(Request $request)
{
try {
$schools = $this->schoolRepository->all($request->all());
} catch (\Exception $e) {
return response()->json(['message' => 'Bad request'], 400);
}
return SchoolResource::collection($schools);
// return response()->json($schools, 200);
}
If I need to add some fields , I can do that either in the model or in the repository.
I often read that this resource notion is important to understand and to use. But for the moment I do not see when or why I should use it. I certainly must not understand something!
There are a couple of primary reasons to use resources to manage your return values even if your resources don't do anything than pass data through today, you may want it to do something different in the future.
A small list of reasons why resources are really useful
1. Data manipulation, specific to clients (i.e. js applications consuming your api)
If you start manipulating data in your models using mutators (getters / setters). Your internal application now has to work with these constraints. Many times its easier to work with the raw data internally and then just allow your resources to manipulate the data for the client.
2. Conforming to an API specification, such as JSON API v1.0
Whilst you will likely need logic in your application to handle schemas like this, your models and controllers should not. The resource has a critical role here to organise the data for your consumer applications in a compliant fashion.
3. The age old mantra, separation of concerns
This goes hand in hand with point 1, it is not a model or a controllers responsibility to map data to what you expect your consumer applications to receive.
Building on your example
You currently have the following in the show route of your resource controller.
public function show(School $school)
{
// return response()->json($school, 200);
return new SchoolResource($school);
}
This need not change, even if your API specification does (reason 1 and 3).
Adding fields, yes, you'll need to add them to your model but lets use this to actually do something meaningful with your resource.
We've created a migration for a new JSON field ratings. Ratings has a data structure like this:
[
{
name: string,
value: float,
}
]
For reasons such as media scrutiny, we never want to expose all the rating data to our publically available front end consumer apps. Instead we want to provide an average score of all ratings.
Now we could do this in the model, but is it the models responsibility to do this? Not really, the model should be handling and dealing in raw / discreetly modified data only. So is it the controllers responsibility? No, the controller coordinates what should be done and is not interested in specific details or the data.
So where do we do this? Enter your resource that was handily already set up.
class School extends JsonResource
{
public function toArray($request)
{
return [
'id' => $this->id,
'name' => $this->name,
'rating' => $this->getRating(),
];
}
/**
* Mean rating rounded to one decimal place
* #return float
*/
protected function getRating()
{
return (round(array_reduce($this->ratings, function($acc, $curr) {
$acc += $curr['value'];
return $acc;
}, 0) / count($this->ratings), 1);
}
}
The resource is where we have manipulated data specifically for our responses and left our internal data modelling un-touched and clean without pollution from specific nuances of our consuming applications.
More importantly, if you just returned return response()->json($school, 200); from your controller, your data structures will not match and you would be exposing some sensitive data to your front end applications.
Additional (24/12/21)
It's worth noting that if, for example, the data that you are manipulating is required by many different views / resources then we have a number of options.
Traits, create a trait that adds the getRating method. Downside, every class that needs this must import and declare the trait. Upside, your code is dry.
Model scopes, add a scope to your model that does the data processing via SQL (or your DB QL of choice). Downside, slight pollution of the model. Upside, super quick.
Append the data to the model (https://laravel.com/docs/8.x/eloquent-serialization#appending-values-to-json) using an accessor that runs the getRating code to set the data on the model. Upside, clean and usable throughout the application. Downsides pollutes the model a little and data only available in the JSON representation of the model.
Decorate the resource. This allows you to intercept and modify/add to the result of the toArray method in the decorated resource. Upsides not many. Downsides, obfuscated and confusing implementation detail. I wouldn't recommend this approach.
Helper function. Rather than have the method on the resource, create a helper that takes the ratings array and returns the result. Upside, simple implementation. Downsides, none that I can thing of.
So after thinking about this alot I think that I would likely do what I originally wrote in this answer. If I need to re-use I would likely create a helper. If I was concerned about performance I would use a model scope to do the calculations in SQL (if possible, remember it's a JSON field). Taking a step further, if many models require this logic, a trait for those models would be my next step (this only applies if you go down the SQL calculation route).
I have been implementing value objects as custom DBAL types in Doctrine 2 and it's been working OK. However I have been wondering if this is the best way. I've thought about using the Post Load listener to instantiate the Value Objects. Also instantiating them through Entity accessors when requested, the advantage with the latter would be that I would not instantiate more objects than I need.
My question is: which method is best? Or is there a better way to do it? Are there any gotchas or unreasonable performance hits with the above?
IMHO, both approaches are equally valuable, while waiting for native support for value objects.
I personally favor the second approach (instantiating them through accessors when requested) for two reasons:
As you mentioned, it offers better performance as the conversion is only done when needed;
It decouples your application from Doctrine dependency: you're writing less code that is Doctrine-specific.
An example of this approach:
class User
{
protected $street;
protected $city;
protected $country;
public function setAddress(Address $address)
{
$this->street = $address->getStreet();
$this->city = $address->getCity();
$this->country = $address->getCountry();
}
public function getAddress()
{
return new Address(
$this->street,
$this->city,
$this->country
);
}
}
This code will be fairly easy to refactor when Doctrine will offer native VO support.
About custom mapping types, I do use them as well, for single-field VO (Decimal, Point, Polygon, ...) but would tend to reserve them for general-purpose, reusable types that can be used across multiple projects, not for project-specific single-field VO where I would favor the approach above.
I'd like to include some additional functions in my Doctrine 2 entities to contain code that I'm going to have to run quite frequently. For example:
User - has many Posts
Post - has a single user
I already have a function $user->getPosts(), but this returns all of my posts. I'm looking to write a $user->getActivePosts(), which would be like:
$user->getPosts()->where('active = true') //if this were possible
or:
$em->getRepository('Posts')->findBy(array('user'=>$user,'active'=>true)) //if this were more convenient
As far as I can tell, there's no way to get back to the entity manager though the Entity itself, so my only option would be
class User {
function getActivePosts() {
$all_posts = $this->getPosts();
$active_posts = new ArrayCollection();
foreach ($all_posts as $post) {
if ($post->getActive()) {
$active_posts->add($post);
}
}
return $active_posts;
}
However, this requires me to load ALL posts into my entity manager, when I really only want a small subset of them, and it requires me to do filtering in PHP, when it would be much more appropriate to do so in the SQL layer. Is there any way to accomplish what I'm looking to do inside the Entity, or do I have to create code outside of it?
I think you should implement the method on the PostRepository rather than on the entity model.
I try to keep all model related logic in the repositories behind "domain specific" methods. That way if you change the way you represent whether a post is active or not, you only have to change the implementation of a single method instead of having to find all the active = true statements scattered around in your application or making changes in an "unrelated" entity model.
Something like this
PostRepository extends EntityRepository {
public function findActiveByUser($user){
// whatever it takes to get the active posts
}
}
I'd like to create an "API-like" layer in my code that effectively cordons-off database access to higher level code. For example, I might have the following function:
class MyApi {
private $my_user_id;
function getContacts() {
$contacts = $em->getRepository('Contacts')->findByOwner($this->my_user_id);
$em->clear();
return $contacts;
}
function getGroups() {
$groups = $em->getRepository('Groups')->findByOwner($this->my_user_id);
//hydrate each group's contacts list
foreach ($groups as $group) {
$group->getContacts();
}
$em->clear();
return $groups;
}
}
I'm using $em->clear() to detach the Entities from the EntityManger before returning them, so my Views can't accidentally modify managed entities. However, I run into problems when I want to compare entities returned by two sequential API functions. Ideally, I'd like a view/controller to contain:
$my_contacts = $myapi->getContacts();
$my_groups = $myapi->getGroups();
foreach($my_groups as $group) {
foreach ($my_contacts as $contact) {
if ($group->getContacts()->contains($contact)) {
echo "{$group->getName()} contains {$contact->getName()}!<br/>";
} else {
echo "{$group->getName()} does not contain {$contact->getName()}!<br/>";
}
}
}
However, since I detached all of the Contacts from the EntityManager at the end of the getContacts API call, the objects returned by $group->getContacts() are different PHP objects than those returned by $api->getContacts(), so the contains() function doesn't work properly.
Do I have any options for "defanging" my entities, making them effectively read-only, without giving up the benefits that the EntityManager provides? (Such as all managed entities representing the same database entry being the same object, being able to further hydrate associated objects after they've been passed back from the API, etc.)
Why would you worry that your views are going to make changes that will be committed back to the database? If your views don't know about the EM (and they shouldn't), any changes they make to the entities will disappear at the end of the request.
The only other option I can think of is to hydrate your results as arrays when they're destined to be fed to the view script. But that gives up a lot of handy functionality.
Maybe this is a little late, but it can be useful for anyone who still needs answer on this issue...
I think there is missing a Domain Driven Design principle here: Command Query Separation.
On every object you can only have two kind of methods:
doSomething() {
//this kind of method can change the internal state
}
getSomething() {
//this kind of method NEVER changes internal state
}
Keeping proper MVC in mind, views should only need get-methods and they can never change a thing.
Detaching you entities is not necessary and no worries are needed, if keeping just CQS and MVC in mind.
I am attempting to create the the business and data layers for my big ASP.NET MVC application. As this is the first time for me attempting a project of this scale I am reading some books and trying to take good care at separating things out properly. Usually my applications mix the business logic and data access layers, and multiple business entities are intertwined in the single class (which has confused me a few times when I was trying to figure out where to add things).
Most of what I have been reading is to separate out the business and data layers. This seems all fine and dandy, but I am having trouble visualizing exactly how to do this in some scenarios. For example, let's say I am creating a system that allows admins to add a new product to the system:
public class Product
{
public int Id { get; private set; }
public string Name { get; set; }
public decimal Price { get; set; }
}
Then I separate out the data access by creating a repository
public class ProductRepository
{
public bool Add(Product product);
}
Let's say I want to require a product's name to have at least 4 characters. I can't see how to do this cleanly.
One idea I had was to expand the Name's set property and only set it if it's 4 characters long. However, there is no way for a method that is creating the product to know the name didn't get set except that Product.Name != whatever they passed in.
Another idea I had is to put it in the Add() method in the repository, but then I have my business logic right there with the data logic, which also means if the Add call fails I don't know if it failed for the business logic or because the DAL failed (and it also means I can't test it using mock frameworks).
The only thing I can think of is to put my DAL stuff in a 3rd layer that gets called from the Add() method in the repository, but I don't see this in any of the domain modelling examples in my book or on the web (that I've seen at least). It also adds to the complexity of the domain models when I am not sure it is needed.
Another example is wanting to make sure that a Name is only used by one product. Would this go in the Product class, ProductRepository Add() method, or where?
As a side note, I plan to use NHibernate as my ORM however, to accomplish what I want it (theoretically) shouldn't matter what ORM I am using since TDD should be able to isolate it all.
Thanks in advance!
I usually approach this by using a layered architecture. How to do this? You basically have the following (ideally) VS projects:
Presentation layer (where the UI stuff resides)
Business layer (where the actual business logic resides)
Data access layer (where you communicate with your underlying DBMS)
For decoupling all of them I use so-called interface layers s.t. in the end I have
Presentation layer (where the UI
stuff resides)
IBusiness layer (containing the interfaces for the
business layer)
Business layer (where
the actual business logic resides)
IDataAccess layer (containing the
interfaces for the DAO layer)
Data access layer (where you communicate
with your underlying DBMS)
This is extremely handy and creates a nicely decoupled architecture. Basically your presentation layer just accesses the interfaces and not the implementations itself. For creating the according instances you should use a Factory or preferably some dependency injection library (Unity is good for .Net apps or alternatively Spring.Net).
How does this impact on your business logic / testability of your app?
It is probably too long to write everything in detail, but if you're concerned about having a well testable design you should absolutely consider dependency injection libraries.
Using NHibernate,...whatever ORM
Having a DAO layer completely separated through the interfaces from the other layers you can use whatever technology behind for accessing your underlying DB. You could directly issue SQL queries or use NHibernate, as you wish. The nice thing is that it is totally independent from the rest of your app. You could event start today by writing SQLs manually and tomorrow exchange your DAO dll with one that uses NHibernate without a single change in your BL or presentation layer.
Moreover testing your BL logic is simple. You may have a class like:
public class ProductsBl : IProductsBL
{
//this gets injected by some framework
public IProductsDao ProductsDao { get; set; }
public void SaveProduct(Product product)
{
//do validation against the product object and react appropriately
...
//persist it down if valid
ProductsDao.PersistProduct(product);
}
...
}
Now you can easily test the validation logic in your SaveProduct(...) method by mocking out the ProductDao in your test case.
Put things like the product name restriction in the domain object, Product, unless you want to allow products with fewer than 4 characters in some scenarios (in this case, you'd apply the 4-character rule at the level of the controller and/or client-side). Remember, your domain objects may be reused by other controllers, actions, internal methods, or even other applications if you share the library. Your validation should be appropriate to the abstraction you are modeling, regardless of application or use case.
Since you are using ASP .NET MVC, you should take advantage of the rich and highly extensible validation APIs included in the framework (search with keywords IDataErrorInfo MVC Validation Application Block DataAnnotations for more). There are lots of ways for the calling method to know that your domain object rejected an argument -- for example, throwing the ArgumentOutOfRangeException.
For the example of ensuring that product names are unique, you would absolutely not put that in Product class, because this requires knowledge of all other Products. This logically belongs at the persistence layer and optionally, the repository. Depending on your use case may warrant a separate service method that verifies that the name does not already exist, but you shouldn't assume that it will still be unique when you later try to persist it (it has to be checked again, because if you validate uniqueness and then keep it around a while longer before persisting, someone else could still persist a record with the same name).
This is the way I do it:
I keep the validation code in the entity class, which inherits some general Item Interface.
Interface Item {
bool Validate();
}
Then, in the repository's CRUD functions i call the appropriate Validate function.
This way all the logic paths are validating my values, but i need to look only in one place to see what that validation really is.
Plus, sometimes you use the entities outside the repository scope, for example in a View. So if the validation is separated, each action path can test for validation without asking the repository.
For restrictions I utilize the partial classes on the DAL and implement the data annotation validators. Quite often, that involves creating custom validators but that works great as it's completely flexible. I've been able to create very complex dependent validations that even hit the database as part of their validity checks.
http://www.asp.net/(S(ywiyuluxr3qb2dfva1z5lgeg))/learn/mvc/tutorial-39-cs.aspx
In keeping with the SRP (single responsibility principle), you might be better served if the validation is separate from the product's domain logic. Since it's required for data integrity, it should probably be closer to the repository - you just want to be sure that validation is always run without having to give it thought.
In this case you might have a generic interface (e.g. IValidationProvider<T>) that is wired to a concrete implementation through an IoC container or whatever your preference may be.
public abstract Repository<T> {
IValidationProvider<T> _validationProvider;
public ValidationResult Validate( T entity ) {
return _validationProvider.Validate( entity );
}
}
This way you can test your validation separately.
Your repository might look like this:
public ProductRepository : Repository<Product> {
// ...
public RepositoryActionResult Add( Product p ) {
var result = RepositoryResult.Success;
if( Validate( p ) == ValidationResult.Success ) {
// Do add..
return RepositoryActionResult.Success;
}
return RepositoryActionResult.Failure;
}
}
You could go a step further, if you intend on exposing this functionality via an external API, and add a service layer to mediate between the domain objects and the data access. In this case, you move the validation to the service layer and delegate data access to the repository. You may have, IProductService.Add( p ). But this can become a pain to maintain due to all of the thin layers.
My $0.02.
Another way to accomplish this with loose coupling would be to create validator classes for your entity types, and register them in your IoC, like so:
public interface ValidatorFor<EntityType>
{
IEnumerable<IDataErrorInfo> errors { get; }
bool IsValid(EntityType entity);
}
public class ProductValidator : ValidatorFor<Product>
{
List<IDataErrorInfo> _errors;
public IEnumerable<IDataErrorInfo> errors
{
get
{
foreach(IDataErrorInfo error in _errors)
yield return error;
}
}
void AddError(IDataErrorInfo error)
{
_errors.Add(error);
}
public ProductValidator()
{
_errors = new List<IDataErrorInfo>();
}
public bool IsValid(Product entity)
{
// validate that the name is at least 4 characters;
// if so, return true;
// if not, add the error with AddError() and return false
}
}
Now when it comes time to validate, ask your IoC for a ValidatorFor<Product> and call IsValid().
What happens when you need to change the validation logic, though? Well, you can create a new implementation of ValidatorFor<Product>, and register that in your IoC instead of the old one. If you are adding another criterion, however, you can use a decorator:
public class ProductNameMaxLengthValidatorDecorator : ValidatorFor<Person>
{
List<IDataErrorInfo> _errors;
public IEnumerable<IDataErrorInfo> errors
{
get
{
foreach(IDataErrorInfo error in _errors)
yield return error;
}
}
void AddError(IDataErrorInfo error)
{
if(!_errors.Contains(error)) _errors.Add(error);
}
ValidatorFor<Person> _inner;
public ProductNameMaxLengthValidatorDecorator(ValidatorFor<Person> validator)
{
_errors = new List<IDataErrorInfo>();
_inner = validator;
}
bool ExceedsMaxLength()
{
// validate that the name doesn't exceed the max length;
// if it does, return false
}
public bool IsValid(Product entity)
{
var inner_is_valid = _inner.IsValid();
var inner_errors = _inner.errors;
if(inner_errors.Count() > 0)
{
foreach(var error in inner_errors) AddError(error);
}
bool this_is_valid = ExceedsMaxLength();
if(!this_is_valid)
{
// add the appropriate error using AddError()
}
return inner_is_valid && this_is_valid;
}
}
Update your IoC configuration and you now have a minimum and maximum length validation without opening up any classes for modification. You can chain an arbitrary number of decorators in this way.
Alternatively, you can create many ValidatorFor<Product> implementations for the various properties, and then ask the IoC for all such implementations and run them in a loop.
Alright, here is my third answer, because there are so very many ways to skin this cat:
public class Product
{
... // normal Product stuff
IList<Action<string, Predicate<StaffInfoViewModel>>> _validations;
IList<string> _errors; // make sure to initialize
IEnumerable<string> Errors { get; }
public void AddValidation(Predicate<Product> test, string message)
{
_validations.Add(
(message,test) => { if(!test(this)) _errors.Add(message); };
}
public bool IsValid()
{
foreach(var validation in _validations)
{
validation();
}
return _errors.Count() == 0;
}
}
With this implementation, you are able to add an arbitrary number of validators to the object without hardcoding the logic into the domain entity. You really need to be using IoC or at least a basic factory for this to make sense, though.
Usage is like:
var product = new Product();
product.AddValidation(p => p.Name.Length >= 4 && p.Name.Length <=20, "Name must be between 4 and 20 characters.");
product.AddValidation(p => !p.Name.Contains("widget"), "Name must not include the word 'widget'.");
product.AddValidation(p => p.Price < 0, "Price must be nonnegative.");
product.AddValidation(p => p.Price > 1, "This is a dollar store, for crying out loud!");
U can use a other validation system. you can add a method to IService in service layer such as:
IEnumerable<IIssue> Validate(T entity)
{
if(entity.Id == null)
yield return new Issue("error message");
}