I have a project that is a results database for several sport event series.
As you an imagine most the content remains more or less the same.
I would like to cache some of the content to save database queries.
The project is build using PHP and is using a custom MVC.
Where would you add the caching logic?
Use Memcached. Something like this, where you cache the results of the query, and try retrieving from cache before DB.
Edit: Added json_encoding the data... json_encode is slightly faster than PHP's default serialization for arrays, and can be used by other applications accessing the data
Memcached by default uses FastLZ compression.
// The ID of the item you're looking for (from $_GET or whatever)
$id = 1;
// Create a memcached instance
$m = new Memcached();
$m->addServer('localhost', 11211);
// Try retrieving the event from memcached
$data = $m->get('event_' . $id);
if ($data) {
// If you found data in memcached, decode it for use in code
$data = json_decode($data);
} else {
// If you didn't find the data in memcached, try retrieving from the DB
$result = mysqli_query('SELECT * FROM events WHERE id = ' . $id);
// If you found results in the DB...
if ($data = mysqli_fetch_assoc($result)) {
// Save them to memcached for future calls
// Note: here, I'm using the optional param to expire it after 1 day
$m->set('event_' . $id, json_encode($data), 86400);
}
}
// Now you can use your data
var_dump($data);
Edited to add comments in code
There are two points where you can use caching in the MVC and MVC-inspired design patterns: the output and data retrieval:
Cache the output:
This would have to be implemented in the views, as part of UI logic (views should be instances, not just dumb templates). Somewhere is same area where view is combining the templates in the response. Only in this case, some of the "templates" would actually be completely without variables.
This way you can cache fragments of HTML in context of MVC .. but this would no apply to your particular use-case. It's better suited for situations, when interaction with data source take too much time. Like when storage is actually REST API.
Cache the data:
To enable this functionality it would have to be performed within model layer. To be precise: in services (classes/instances, that mostly contain interaction between domain and storage logic).
If you have a fully implemented model layer, where you separate application, domain and storage logic, then implementation of caching would simply look as different form of storage.
$user = new User;
$cache = new UserCacheMapper;
$user->setId( 42 );
if ( ! $cache->fetch( $user ) )
{
$storage = new UserSQLMapper( $pdo );
$storage->fetch( $user );
$cache->store( $user );
}
// the $user object has been initialized
The initialization of objects actually should be performed by factories within the service, but this is a simplified example
This way you can create application without caching, and only later add it by modifying the services(that are responsible for application logic). Neither the domain objects (domain logic) nor the data mappers (storage logic) would have to change.
Objects can be cached using Memcache(d), which is most useful for multi server setups. For a single server, you can store things in an APC/Xcache etc which offer caching facilities.
I would cache the data in the dataaccess method.
I would used memcached as its really easy to build a cacheing solution using it http://memcached.org/
I normally put the caching logic in the controller although the model may normally be a more correct place for it, reason being that the context of model use can affect caching strategies
Putting it in the model makes the caching strategy sit with the rest of the data access functionality which is correct, it means that you can swap models and the caching code moves with it. Where this can fall down is where you have complex invalidation that cannot be put in the model.
“There are only two hard things in Computer Science: cache invalidation and naming things” Phil Karlton
You say you're using your own MVC pattern framework so it's hard to give a specific recommendation.
There are a few places you can cache.
If you use HTTP properly (idempotency, etags, cache-control headers, etc), you might benefit from placing the caching layer outside the application and using a forward cache like varnish to cache whole pages. However, it's very easy to get HTTP wrong, so this may not be the way to go. For example, if you have user accounts and the same url produces different server output depending on what user is logged in, you can't use HTTP caching because your resource depends on cookie state. (What you should do is put the user into the url, E.g. /mysite/{userid}/profile instead of /mysite/profile.) You may still be able to use varnish via its more advanced features, but it will be more difficult.
You say you are just interested in caching database query results, so I'll address that.
If you have a few well-defined queries where you want to cache a database response, you can put the logic in the controller: before you pass a model on to the view, cache it explicitly. This solution produces a messy codebase if you have multiple places to cache. Also, if you are retrieving the same data in different controllers, you will need to carefully and manually ensure that all controller code that retrieves the same models also consults the cache and uses the same cache key. Obviously, it also becomes difficult to turn caching on and off.
A cleaner solution is to wrap your models in a way that caches results transparently. This means you can add caching declaratively without making substantial changes to your controllers or models. However, this requires having a very well designed model api, which you may not have.
Related
I'm developing a PHP MVC REST API which will have OAuth for authenticating if the call can be performed.
So my plan is to develop it for an Angular 2/4 app which will handle the API calls.
The idea was to create a structure where my domain for example test.com will have a subdomain api.test.com.And from it the API calls will be requested.
The thing that i would like to confirm before i start building this is my MVC backend structure.
Ref.Pic
Model will have all the logic
View will be the api.test.com/api/call presentation.Outputing the JSON in my case.
Controller will accept input exmp:the api.test.com/api/call call the logic in the Model if the call is correct.Than the call will react on the view where presenting the JSON.It would hold the OAuth also....
I'm trying to understand the whole concept of this, since i have tried several times to build it and every time i end up in a mess of code.I'd like to see if my understanding of the project above makes sense.
Thank you
There are multiple issues, that you will encounter as you try to apply SoC principle in your codebase.
And, what to do with communication between views and controllers, is one of the more visible ones. That's because, if you mess it up, there are no abstractions to hide it all behind.
The two major approaches are Supervising Controller and Autonomous View (which has no article, but you can deduce some of it from this and this).
Supervising controller
This approach is best suited for smaller applications (well .. for large values of "small", since really small projects don't really need the architectural bloat of MVC). It essentially looks like this:
/* in a controller */
public function verifyEmail(Request $request)
{
$identity = $this->search->findEmailIdentityByToken(
$request->get('token'),
Identity::ACTION_VERIFY
);
$this->registration->verifyEmailIdentity($identity);
$body = [
'status' => 'ok',
];
return new JsonResponse($body);
}
Essentially, what you have there is a controller, that interacts with the business model and (when necessary) populates the view with data. Then it causes the view to be rendered and returns the response.
In my own experience, I have found this to be the best approach to use, when writing backend applications, that are expected to only be manipulated via REST-like API.
As you see in the example, the "view" in this case is extremely trivial. It is basically array, that you render as JSON (which the provided code would actually do - it's copied from a real project).
Note:
If your intention is to fully implement REST as it was proposed (not just the REST-like resource endpoints) and/or
have functionality of resource expansion, then this approach might be wrong and even harmful.
Autonomous View
When your presentation logic becomes complicated or have to provide different UIs for the same application with the same functionality (like having single app with both website and REST API, with both xml an json interface), then using Supervising Controller becomes a ball and chain around your neck. Your controllers start to grow uncontrollably and your project can be described as "legacy codebase", before it even reaches production.
And that's where you use this approach.
You use views and controllers as completely separate classes and you interact of their instances at the same layer (for example: bootstrap stage). It ends up looking something like this:
/* in /src/application.bootstrap.php */
$command = $request->getMethod() . $parameters['action'];
$resource = $parameters['resource'];
$controller = $container->get("controllers.$resource");
if (method_exists($controller, $command)) {
$controller->{$command}($request);
}
$view = $container->get("views.$resource");
if (method_exists($view, $command)) {
$response = $view->{$command}($request);
$response->send();
}
Again, example from a different live project, which also uses a DI container. In this case there is only one UI (hence, no "type" prefix, when making a view instance), which mean that the code can take advantage of 1:1 relation between controllers views (it would be 1:n, if you need multiple UIs).
The controller in this case basically only "writes" to the model layer. And the view (which also has access to services from model layer) only performs "reads" and extracts only the information, that it requires for populating templates and rendering them.
And, if your presentation logic grows further, it is a good idea to start adding presentation objects, that will contain the repeating parts of the presentation logic (e.g. deciding, which menu item in the sidebar has to be expanded and which submenu item has to be highlighted), that are common for multiple views.
If your backend application only deals with API, then this approach might be too complex, unless you are doing one of the things mentioned in the "note" part.
... maybe this helps a bit
Yes, That makes sense. I suggest using the Laravel framework instead. Or the OctoberCMS even better.
I have developed web application without using any framework via PHP. My application mainly have two type of files - frontends and backends. The first type may contain HTML, PHP, CSS, JavaScript (jQuery) and the backends - only PHP. I have one class called pg_db_connection which makes connection with the database and one class session which create user's web session(php's function session_start()) and maintain some variables like "username", user's id in the users database table etc.
The pg_db_connection class has a property $link which is a database resource gained from pg_connect(). This class also have some functions like query($query, $b_result = false, &$affected_rows = null), insert($table, $values, $columns = null, &$affected_rows = null), begin(), commit(), rollback(), and more. In the start of every frontend file I create object of type session and perform:
$db = new pg_db_connection($db_config,$log_mng);
$session = new session($db);
#if the session is not active go to login.php frontend and force the user to login
if(!$session->is_active())
{
header("Location: /html/admin/login.php?url=" . urlencode($_SERVER['REQUEST_URI']));
exit;
}
# If session is active proceed below
# Auto refresh the session
$session->autoReresh();
# Check if the current user have privileges to access this frontend file (second param is file path, third - file name)
if(!($session->passpermit($session->user_id(), $_SERVER['SERVER_ADDR'], dirname(__FILE__)."/", basename(__FILE__))))
{
header("Location: /html/admin/access_denied.html");
exit;
}
Session class store user_id, username and more in $_SESSION. Connection to the database is needed, because the files, which web user have permissions to access are stored in the database. If I want to load any dynamic data in this frontend file I use jQuery's post or load functions and make call to one backend file. This backend file in the most cases include pg_db_connection, execute some database queries, if also needed - do some more work upon the data(wrap with HTML tags, or format the array somehow and then json_encode it), and then retrieve HTML or JSON to the frontend file. Then in the jquery's load or post callback method this HTML is written where needed, or the JSON is transformed somehow to HTML and again written somewhere in the HTML.
I am wondering if I use any kind of known architectural pattern. Or which architectural pattern is closest to the described approach?
To the best of my knowledge, your application architecture doesn't follow any specific architectural pattern specifically.
Generally you use a client(frontend) - server (backend) architecture and you fetch data from the frontend with JavaScript/Ajax requests.
You use don't specify the architecture of your business logic code...so there is no way to tell whether you use a MVC pattern etc...
Check out this link to learn more:
https://softwareengineering.stackexchange.com/questions/158260/is-there-any-design-pattern-except-mvc-for-web
I also recommend you to read this write-up to get a better understanding of web application design decisions:
Web Application Design Patterns
From the list in this link, I would say you use the following design patterns:
Request-Processing: Page Controller (apparently you have a single entry class where you control authentication and authorization)
Presentation: Supervising Presenter (if I got you right, you do the main logic in the server, but you then delegate some UI/JSON-Content replacement tasks etc. to the Frontend JavaScript)
Page Layout (UI): Transform/Two-Step View (you create with jQuery some HTML out of JSON right?)
Persistence: Transactional Data Store (because you use begin(), commit() , rollback())
Some criticism:
pg_db_connection implies you have to use postgres DB I guess?
...so you can't easy switch your database...and you have to deal with error-prone and security-risky low level SQL queries...
Custom session handling is also rather error-prone with many pit-falls...
e.g.
header("Location: /html/admin/login.php?url=" . urlencode($_SERVER['REQUEST_URI']))
...might lead to a redirect-vulnerability...and I don't even want to know what you are doing in login.php...
Regarding exit; you may want to read here why exit() is sub-optimal:
Best Practice for PHP exit()
Anyway, there are reasons why people actually NOT writing their own web-application architecture from scratch and rather get inspired-by or use a PHP framework:
Make speed development possible
Provide well-organized, reusable and maintainable code
Let you grow over time as web apps running on frameworks are scalable
Spare you from the worries about low-level security of a site
Follow the MVC (Model-View-Controller) pattern that ensures the separation of presentation and logic
Promote modern web development practices such as object-oriented programming tools
Check out some of the currently modern frameworks presented in this blog post:
http://www.hongkiat.com/blog/best-php-frameworks/
(thats also the source for the before-mentioned framework usage reasons...)
Maybe something fits your use case without being too slow/bloated/etc...
How far do I break down individual tasks within a typical scenario of "Web application reacts to user input"?
For example, in the case below, say a scenario is "User submits a form, causing user data to be turned into an Object (technical detail) and then saved into the database" .
I am using various services to get, filter, object-ify, and save data. Specifically, for example, in my $domainObject = ... line below solely copies data from array into an object (similar to this What is a name for a pattern where it receives data or asks for data and returns back an object?)
I am asking, if by continuing to separate individual concerns I come across, into various classes, services, and methods, am I making things harder for myself or future maintainers in the long run?
class Controller
{
//saves a domain object acquired from an HTML form & other sources
function saveAction()
{
// acquire data from GET, POST, COOKIE, SESSION, database, et
$inputData = $this->inputService->acquireData();
// clean data
$filteredData = $this->filterService->filter($inputData);
// marshall data into an object
$domainObject = $this->objectService->createObject($filteredData);
//save object into a database
$id = $this->repository->save($domainObject);
// Send $id to View
return new ViewModel(array(
'id' => $id
);
}
For Clarity
Let's call "parameter passing" as "wiring".
So, first, my wire is $inputData, which I receive from inputService.
I take that wire and feed it into filterService, which returns the
other end of the wire called $filteredData.
I take that end of wire and feed it into objectService.
In return I get $domainObject end of the wire.
I take that end and feed it into repository, and receive back ID
I take the $id end of wire and run it into my ViewModel, and that's the endpoint.
^^^^ The above is all the wiring that I do and that needs to happen when I use Separation of Concern to separate my code into various code constructs of inputService, filterService, objectService, repository, ViewModel.
The wiring connects them together.
I can "cheat" and merge some code constructs together to minimize on passing the wire. (minimize passing the parameters everywhere).
And that is what my question is about.
Question
Is wiring up of the individual code constructs (parameter passing between various services) a good thing? Should I do more? Should I do less? Is there a technique I'm not aware of that makes this a non-issue?
I would say that it depends of the business logic and the domain of the problem you're trying to solve. If you see frameworks like Ruby On Rails, or Laravel, they try to use MVC to tackle common web app problems. However, these frameworks start to get fat (for example, you can find controllers or models with more than 2000 lines of code, i.e the famous User model with a lot of business logic).
This has popularized two approachs.
The use of microservices in different technologies instead of monolithic applications.
The use of OOP concepts like concerns (traits in PHP), composition, mixins for behaviors, engines for splitting logic and more.
So I would say that if you have a simple app, with no future intentions of making it grow with hundreds of features, a simple mvc flow with helpers can be enough. If your app is planning to grow a lot, you should consider an alternative as mentioned before.
This is a very debated topic, and there are several articles of great programmers, like this one from David Heinemeier Hansson. Also this is pure gold from Sandy Metz in railsconf. And other nice resource is this question.
Background
This is a long and complicated question. I'm using php/MySQL as an example (since it's an actual example) but this could theoretically apply to other languages. Bear with me.
MVC Framework with no ORM
I'm creating an application that uses its own framework. For a variety of reasons, the following answers to this question will not be accepted:
Why don't you just use X framework?
Why don't you just use X ORM?
This application does its own queries (written by me) and that's how I'd like it to stay for now.
Business Logic?
"Business Logic" seems to be a meaningless buzzword, but I take it to essentially mean
The queries and the logic that builds the result set based on those queries
I've also read that the Model in an MVC should do all the business logic.
User.php is 884 lines
Now that I've gotten my app working fairly well, I'd like to refactor it so as not to have such abominations. User.php is essentially the model for Users (obviously). There are some responsibilities I see in it that I could easily pluck out, but a major hurdle I'm running into is:
How can I reconcile SOLID with MVC?
The reason that User.php has grown so large is because I do any query that requires a User member in that file. User is used for a ton of operations (it needs to do so much more than just CRUD), so any query that needs userid, username, etc. is run by a function in this file. Apparently the queries should be in the model (and not the controller), but I feel that this should definitely be split up somehow. I need to accomplish the following:
Create an API that covers all of these necessary queries in a compartmentalized way
Avoid giving access to the DB connection class when it's not necessary
Add User data to the view (User.php is doing that right now -- the view object is injected by a setter, which I think is also bad).
...so what I could do is create other objects like UserBranchManager, UserSiteManager, UserTagManager, etc. and each of those could have the relevant queries and the DB object injected to run those queries, but then how do they get the coveted User::$userid that they need to run these queries? Not only that, but how could I pass Branch::$branchid? Shouldn't those members be private? Adding a getter for them also makes that pointless.
I'm also not sure where to draw the line of how much an object should do. A lot of the operations similar but still different. A class for each one would be huge overkill.
Possible Answer
If I can't get any help, what I'll do (or at least try to do) is have a dependency injection container of some kind build dependencies for the objects above (e.g. UserBranchManager) and inject them into the relevant controller. These would have a DB and Query object. The Query object could be passed to low level models (like User) to bind parameters as needed, and the higher level models or whatever they are called would give the results back to the controller which would add the data to the template as needed as well. Some possible hurdles I see are creating proper contracts (e.g. the UserController should preferably depend on some abstraction of the user models) but some specifics are inevitably required, especially when it comes to the view.
Can anyone offer some wisdom in response to my rambling question?
Response to #tereško
He has provided a great answer not only here, but also at How should a model be structured in MVC?
Code
As requested, here is some extremely pared down code (basically services one request). Some important notes:
Right now, controllers are not classes, just files
The controller also handles a lot of the routing
There are no "view" objects, just the templates
This will probably look really bad
These are also things to improve, but I'm mostly worried about the model (User in particular since it's getting out of control):
#usr.php -- controller
$route = route();
$user = '';
$branch = '<TRUNK>';
if (count($route) > 0) {
if (count($route) > 1) {
list($user, $branch) = $route;
}
else {
list($user) = $route;
}
}
$dec = new Decorator('user');
$dec->css('user');
if (isset($_SESSION['user']) && $_SESSION['user']->is($user)) {
$usr = $_SESSION['user'];
}
else {
$usr = new User(new DB, $user);
}
$usr->setUpTemplate($dec, $branch);
return $dec->execute();
# User.php -- model
class User {
private $userid;
private $username;
private $db;
public function __construct(DB $db, $username = null) {
$this->username = $username;
$this->db = $DB;
}
public function is($user) {
return strtolower($this->username) === strtolower($user);
}
public function setUpTemplate(Decorator $dec, $branch) {
$dec->_title = "$this->username $branch";
// This function runs a moderately complicated query
// joining the branch name and this user id/name
$dec->branch = $this->getBranchDisplay($branch);
}
}
Questions about answers
Answer here:
You talk about leaving off caching/authentication/authorization. Are these important? Why aren't they covered? How do they relate to the model/controller/router?
The Data Mapper example has the Person class with methods like getExemption, isFlaggedForAudit .. what are those? It seems like those calculations would require DB data, so how does it get them? Person Mapper leaves off select. Isn't that important?
What is "domain logic?"
Answer 5863870 (specifically the code example):
Shouldn't these factory objects be abstractions (and not rely on creation via new) or are these special?
How would your API include the necessary definition files?
I've read a lot about how it's best for dependencies to be injected in the constructor (if they're mandatory). I assume you set the factories in this way, but why not the objects/mappers/services themselves? What about abstractions?
Are you worried about code duplication (e.g. most models requiring an _object_factory member in their class definition)? If so, how could you avoid this?
You're using protected. Why?
If you can provide any specific code examples that would be best since it's easier for me to pick stuff up that way.
I understand the theory of what your answers are saying and it's helped a lot. What I'm still interested in (and not totally sure of) is making sure that dependencies of objects in this API are handled in the best way (the worst would be new everywhere).
Dont confuse SOLID (You can get a good explanation of what it is on my blog at: http://crazycoders.net/2012/03/confoo-2012-make-your-project-solid/
SOLID is great when considering the framework that goes around the application you are trying to build. The management of the data itself is another thing. You can't really apply the Single Responsibility of the S of SOLID to a business model that RELIES on other business models such as User, Groups and Permissions.
Thus, you have to let some of the SOLID go when you build an application. What SOLID is good for, is to make sure your framework behind your application is strong.
For example, if you build your own framework and business model, you will probably have a base class MODEL another for DATABASEACCESS, just remember that your MODEL shouldn't be aware of how to get the data, just know that it must get data.
For example:
Good:
- MyApp_Models_User extends MyApp_Framework_Model
- MyApp_Models_Group extends MyApp_Framework_Model
- MyApp_Models_Permission extends MyApp_Framework_Model
- MyApp_Framework_Model
- MyApp_Framework_Provider
- MyApp_Framework_MysqliProvider extends MyApp_Framework_Provider
In this good part, you create a model like this:
$user = new MyApp_Models_User(new MyApp_Framework_MysqliProvider(...));
$user->load(1234);
This way, you will prevent a fail in the single responsibility, your provider is used to load the data from one of the many providers that exist and your model represents the data that you extracted, it doesn't know how to read or write the data, thats the providers job...
Bad way:
- MyApp_Model_User
- MyApp_Model_Group
- MyApp_Model_Permission
define('MyDB', 'localhost');
define('MyUser', 'user');
define('MyPass', 'pass');
$user = new MyApp_Models_User(1234);
Using this bad method you first of all break the single responsibility, your model represents something and also manages the input/ouput of the data. Also, you create a dependency by stating that you need to define constants for the model to connect to the database and you completly abstract the database methods, if you need to change them and have 37 models, you'll have TONS of work to do...
Now, you can, if you want work the bad way... i still do it, i'm aware of it, but sometimes, when you have crappy structure and want to refactor, you can and should work against a principle just to refactor correctly and slowly, THEN, refactor a little more and end up with something SOLID and MVC looking.
Just remember that SOLID doesn't apply to everything, it's just a guideline, but it's very very good guideline.
Well .. it depends on what is actually inside your ./user.php file. If i had to guess, you would be a situation, where your user "model" has too many responsibilities. Basically, you are violating single responsibility principle and not sure how to go about fixing that.
You did no provide any code .. so , lets continue with guessing ...
It is possible that your user "model" is implementing active record pattern. This would be the main source of SRP problems. You could watch this part of lecture slides. It will explain some of it. The point would be, instead of using active record, to go with something similar to a data mapper pattern.
Also, you might notice that some of the domain logic, which works with User class instances, seems to happen outside your "model". It might be beneficial to separate that part in a different structure. Otherwise you will be forcing the domain logic inside the controller. Maybe this comment could shine some light on the whole subject.
Another thing you might have crammed inside your user "model" could be parts of the authorization (no to confuse with authentication) mechanism. It could be pragmatic to separate this responsibility.
Update
You talk about leaving off caching/authentication/authorization. Are these important? Why aren't they covered? How do they relate to the model/controller/router?
Caching is something that you would add later in the application. The domain objects do not care where the data comes from. For that reason you can wither add the caching with in the service-level objects or inside the existing data mappers. I would advise to choose former option, because changing existing mappers might have unforeseen side effects. And because it would just over-complicate the existing mappers.
namespace Application\Service;
class Community{
public function getUserDetails( $uid )
{
$user = $this->domainObjectFactory->build('User');
$cache = $this->cacheFactory->build('User');
$user->setId( $uid );
try
{
$cache->pull( $user );
}
cache( NotFoundException $e)
{
$mapper = $this->mapperFactory->build('User');
$mapper->pull( $user );
$cache->push( $user );
}
return $user->getDetails();
}
}
This would illustrate a very simplified acquisition of user information based on user's ID. The code creates domain object and provides it with ID, then this $user ovject is used as condition to search for cached details or, if it fails, fetching that pulling that information from DB via the data mapper. Also, if that is successful, the details are pushed into the cache, for next time.
You might notice, that this example did not handle situation, when mapper cannot find such user with such ID in storage (usually - SQL database). As I said , it's a simplified example.
Also, you might notice, that this sort of caching can be easily added on case-by-case basis and would not drastically change how your logic behaves.
Authorization is another part, which should not directly influence your business logic. I already linked my preferred way for providing authentication. The idea is that, instead of checking for credentials inside controller (like here, here, here or here), the access rights are checked before you execute a method on the controller. This way you have additional options for handling the denial of access, without being stuck within a specific controller.
The Data Mapper example has the Person class with methods like getExemption(), isFlaggedForAudit() .. what are those? It seems like those calculations would require DB data, so how does it get them? Person Mapper leaves off select. Isn't that important?
The Person class is a domain object. It would contain the part of domain logic, that is associated directly with that entity.
For those methods to be executed, the mapper should at first load the data. In PHP it would look something like this:
$person = new Person;
$mapper = new PersonMapper( $databaseConnection );
$person->setId( $id );
$mapper->fetch( $person );
if ( $person->isFlaggedForAudit() )
{
return $person->getTaxableEearnings();
}
The names of methods in the PersonMapper are there as an example, so that you would understand, how the class is supposed to be used. I usually name methods fetch(), store() and remove() (or push/pull/remove ... depends on how much GIT have I been using). IMHO, there is no point to have a separate update() and insert() methods. If object's data was initially retrieved by mapper, then it is an UPDATE. If not - it is an INSERT. You can also determine it whether the value, which corresponds to PRIMARY KEY has been set or not (in some cases, at least).
What is "domain logic?"
It is part of the code which knows how to create an invoice and apply discount price for specific products. It's also the code which makes sure, that you do not submit registration form, you do not state that you have been born in 1592.
The MVC is made from two layers: presentation (can contain: views, templates, controllers) and model layer (can contain: services, domain objects, mappers). The presentation layer deals with user interaction and responses. The model layer deals with business and validation rules. You could say that domain business logic is everything in model, that does not deal with storage.
I guess there is no easy way to explain.
Shouldn't these factory objects be abstractions (and not rely on creation via new) or are these special?
Which "factory objects", where? Are you talking about this fragment ?
$serviceFactory = new ServiceFactory(
new DataMapperFactory( $dbhProvider ),
new DomainObjectFactory
);
$serviceFactory->setDefaultNamespace('Application\\Service');
That whole code fragment is supposed to be in bootstrap.php file (or you might be using index.php or init.php for that). It's the entry point for the application. It is not part of any class, therefore you cannot have *tight coupling" there. There is nothing to "couple with".
How would your API include the necessary definition files?
That fragment is not entire bootstrap.php file. Above that code are includes and initialization for autoloader. I am currently using dynamic loader, which lets classes from same namespace to be located in different folders.
Also, such autoloader is a development-stage artifact. In production code you have to use loader, which works with predefined hashtable and does not need to actually walk the tree of namespaces and locations.
I've read a lot about how it's best for dependencies to be injected in the constructor (if they're mandatory). I assume you set the factories in this way, but why not the objects/mappers/services themselves? What about abstractions?
What are you talking about ?!?
Are you worried about code duplication (e.g. most models requiring an _object_factory member in their class definition)? If so, how could you avoid this?
Did you actually LOOK at how old that code fragment in comments was ?!?!?
You're using protected. Why?
Because, if values/methods are defined with protected visibility, you can access them when you extend the original class. Also, that code example was made for old version of answer. Check the dates.
And no. I will not provide any specific code examples. Because each situation is different. If you want to do copy-paste development, then use CakePHP or CodeIgniter.
I'm thinking about using CodeIgniter for a new project. I was reading the user-guide for CI and I noticed a few things. In all their examples, they seem to put all the logic in the Controller and just use the model to get and set data. I like to put all my logic in my Model.
Are all of their functions universal to all 3 parts (model, view, and controller) or will there be problems if trying to do logic in the model as opposed to the controller.
Also, are all variables accessible to all 3 parts (model, view, and controller). If I wanted to know if a user was logged in within the view, would I have to pass that information to the view from the controller or is it already accessible within the view?
Also, I noticed that session data is stored within cookies, even though they are encrypted. Is the encryption safe enough to use, beause im more used to using sessions. Also, how long are these cookies stored by default? I was a little confused about that part, if anybody can clear that up.
If you have any other tips to help my learning this new framework, I would appreciate it.
Thanks
EDIT: I like to use Fat Models and skinny controllers, so that I can use the same functions in more than one place.
Just read about Kohana, I think I'll look more into that
You have made a lot of assumptions from some basic examples which are not entirely correct.
Controllers should contain interaction logic.
That means that your Controllers should just be saying what models, views, libraries, etc should be used based on what the user is doing.
Models contain data logic.
This can be your business logic, tax calculations, all sorts of data related work. The examples in the userguide suggest just using Models as a "dump wrapper for the database" but you can do anything with them. The model simple represents your data and the rest of your application should not care where it came from.
My models contain a mixture of XML file parsing, REST method calls and of course, some ActiveRecord queries.
Views just show stuff, therefore has no idea about login/logout state. You would of course need to tell it this from your controller (or from global code such as MY_Controller, which IMHO almost every decent sized application needs).
Sessions stored as encrypted cookies are perfectly safe. They would only be able to decode them if they knew your application encryption key, but that is very unlikely unless you have not set one; in which case you only have yourself to blame.
If storing sessions in cookies is not your cup of tea, you can store session values in the database to keep them even more secure, or grab a different session library to work with.
The thing to remember with CodeIgniter is that it only suggests ways to work, if you don't like it, extend, override or replace.
they seem to put all the logic in the Controller and just use the model to get and set data.
CodeIgniter expects very little logic in its models, and instead gives you a very dumb SQL wrapper for returning simple arrays of POD types to represent your data. It even puts a lot of validation code into the controllers, which (in my opinion) is incorrect and repetitive. I've rolled my own solution for Rails-style in-model validation and dynamic find method, allowing things like
// inside model:
// username must be 8 to 25 chars long
$this->validates_length_of('username', 8, 25);
// dynamically handled via __call()
$this->User->find_first_by_username('john'); // Return object or null
$this->User->find(); // select *
$this->User->find_by_group('admin'); // return 0 or more records
but AFAIK there isn't any built-in way of doing similar things with CodeIgniter.
Also, are all variables accessible to all 3 parts
No; you have to manually pass your variables from your controller to your view, and there is no sharing of variables with models/controllers or models/views.
I believe the method suggested by CodeIgniter:
<?php
function users() {
$data['users'] = $this->User->find();
// must use $data['users'] for controller logic; verbose and annoying
$this->load->view('users/index', $data); // $users defined for view
}
?>
can be improved by using PHP's compact keyword:
<?php
function users() {
$users = $this->User->find();
// now we can use $users more easily
$this->load->view('users/index', compact('users'));
}
?>
I noticed that session data is stored within cookies
CodeIgniter can store session data in a database; see $config['sess_use_database'] in config/config.php. There are other config settings in there that pertain to the lifetime of the session cookie.
I'm inclined to say that the only thing CodeIgniter does well is their documentation, read more about session configuration and their implemntation of active record (really a language-independant SQL wrapper which has nothing to do with the Active Record pattern)
CodeIgniter is based on the Model-View-Controller development pattern. The model represents your data structures and should be used just for that.
I would follow that convention, especially if you want to learn the new framework.
AFAIK, the session id is encrypted and stored in cookies, but session data is stored in local database.
The main idea of MVC is such division. But models are not restricted to just direct access to data, they can perform various data manipulation. The idea is to represent objects(and sets of objects) stored in database as php objects, so if it seems logical to have some function in you object - it's as much logical to have it in your model.
I think the misunderstanding here is that so many web applications have hardly any logic outside some simple data processing, that developers are getting used to it.