I´m working on a small Web-Application which will be having a private messaging system. While a user is signed in his received or written messages will be displayed in a toolbar area inside a dropdown menu. Nothing new :-)
The toolbar will be displayed most of the time while a user is travelling through the page. So instead of injecting the inbox implementation into each controller which might be called through routes.php I´m thinking about using the new blade function #inject.
This would look like this (abstracted)
Toolbar view calls ControllerMethod via #inject
ControllerMethod calls injected InterfaceMethod (constructor based Injection)
Service Container serves Implementation
ImplementationMethod returns inbox
But I´m not sure if this is a nice design pattern because I´m relatively new to dependency injection in general. I´d appreciate some thaughts.
There are 2 things here that are wrong to me.
1) Laravel's #Inject view directive does not actually do any sort of "Dependency Injection", despite it's name suggesting so. It is in fact using service location, a pattern which is widely considered anti-pattern.
Basically, via #Inject, the view has access to anything in the container. It can get anything it wants. It doesn't get told what it should have. That's the principle difference between dependency injection and service location.
2) Injecting services into the view directly will undoubtedly mean that you are adding more complexity to your application because you're added more places where services can be injected into your templates. While it may make things quicker and simpler looking short-term, long-term it will make things more difficult to work with.
3) How will you test how you fetch and control data if that's happening in your view? You'd likely have to use functional testing, which, while not a bad thing to be doing, is still not going to be as useful as unit testing for something like this.
I'd recommend sticking to how things are usually done in regards to DI, and actually use DI.
Related
This question is a bit hard to explain, but I'll try my best.
Say, I am creating an job add aggregator site. For this, I have 10 job sites I will crawl through, parse the HTML
and get all the juices.
Now, since each sites template, url and the amount of information they contain is unique, something tells me the crawling part
should be organized separately.
Normally, I could put it all together in
class CrawlerController extends Controller {
public function fooDotComAction(){
}
public function barDotNetAction(){
}
}
You can see the above is still better than dumping all my crawler logic inside the DefaultController,
but even my example doesn't seem efficient, or modular.
It seems like a bad practice, I am wandering if there is some sort of feature in Symfony that
provides an implementation or guide for such problems.
Your question is too broad but you have find the design pattern who will fit your needs then implement it. You will need to create php class and to declare them as services.
Symfony promotes the ideas of service-oriented architecture and has powerful solution for separation of concerns: The Dependency Injection Component. In short, this component provides implementation of the Service Container: a tool for configuration, binding and creation of the separate service objects.
Your business code will be contain in domain services and your controller will just organize the input and output and call the domain services
check out https://codereviewvideos.com/blog/symfony-compiler-pass-tutorial/
and the 2 linked videos and explanations. (1, 2)
it will show you how you can, in a clean way, seperate each 'crawler', using tagged services and a compiler pass, which i think would be a clean way of doing this .
i got a little bit confused about decoupling, separating of concerns, the framework (Symfony2) and my business model. Let me explain :)
In modern web based projects we're supposed to have a thin controller. This seems to be best practice nowadays. Also it seems to be best practice to decouple the framework and the business model. And to do separation of concerns. I'm fine with all of that. Using events/event dispatching works like a charme to solve these concerns.
But now i have a task where i need to do the following things:
read a cookie
save some data to the database based on the contents of the cookie
delete the cookie
First my understanding of working with cookies in Symfony2:
I read the cookie using the request object
I manipulate the cookie using the response object
I should avoid using \setCookie directly
And that's the point where i got confused. Because:
I would assume that all of the three steps are part of my "task" i need to perform. So it would make sense to do all of the stuff in the same class/piece of business model.
I want to avoid mixing up my business model and third party components (like the request/response) as much as possible.
Now i have two options - But both of them are feeling wrong in some way:
Being strict on decoupling framework and business model - Reading/writing the cookie will be left in the controller, since framework components are involved. The persisting is done in the business model. - BUT: Not all the code belonging to the task are in one place now.
I also could have all of the code necessary to perform the task in one place. But then i would need to make the request and the response available within my service, which i try to avoid.
How do you guys handle this kind of issues ?
Thanks,
Stephan
I suppose that you have to make a choice: if you're trying to avoid injection of the request into a service you have to manipulate it into the controller directly.
Of course you could use a private controller that you can call from an arbitrary action and where you can store all the code: that way you could follow the DRY methodology that is always a good practice and you'll avoid injection.
In my vision of symfony however, I would use a service with injection keeping controllers small and not heavy. In that service you could store all business logic related to controller's object manipulation.
This answer, however, could vary from devel to devel so it's hard to find the right methodology
Regarding decoupling from the framework, I wrote a blog post about that here http://thesolidphp.com/decoupling-application-from-framework/
You could separate the cookie handling by creating your own class that will use the Symfony cookie manager. That class should implement an interface like CookieStorage. Your domain objects will only depend on that interface. A concrete implementation could be SymfonyCookieStorage, that will call the Symfony cookie handling objects. Now your business objects are separated from the Symfony cookie manager.
It's the same concept I wrote about in the blog post. That way you could decouple basically everything and keep you objects unaware they are using Symfony.
Earlier I asked this question:
should-i-create-an-object-or-work-with-an-array
I am now trying tho think beyond the concept that I was working with. Please share your thoughts with me. I want to GET this.
If I would setup an MVC in combination with a data mapper, would this be logical, for a forum for instance:
All important things are entities. Post, Thread, User, Forum.
Basically I see a controller as a page. It may choose to show different templates (e.g. list, or form), but it IS the page, more or less.
Via the router I would have the needed controller loaded, to get the data and have it displayed in my template.
Now how would this work, for displaying all posts in a thread:
route is set to thread-> load thread controller -> controller asks entities (post, user) for the info -> entities tell the mapper what they need -> mapper gets it from database and returns it to entities -> entities return info to controller -> controller returns info to view -> view displays.
Is that the right idea?
Now where did the "model" go then, from the MVC? Or am I missing steps?
I do not want to use third party tools, I want to build it from scratch, to understand everything that goes on.
How do I start this off right?
I tend to see the page as the sum of the controller (the logic required prior to rendering) and the view (which determines what the page looks like). In general, I would recommend that you don't write your own first, since you'll be working to a design pattern that you've not yet fully understood. I think it would be better to pick a popular PHP framework and see how it is implemented, and then if you are still minded to, try writing your own. Coding it all of this is a lot of work, in my view, especially if you want to write an ORM too!
Although we shy away from framework recommendations on Stack Overflow, I understand from comments here that Symfony2 is thought to be one of the best implementations of this design pattern, in particular because of its use of dependency injection. Do read some of the questions here with the 'mvc' tag too - there's plenty that can be picked up. For what it's worth, I wouldn't get hung up too much on design patterns (i.e. whether framework X implements pattern Y) - so long as your apps are modular and easily testable, that's a big win.
I have almost completed a PHP project, using MVC, jQuery and Ajax. It is pure PHP project. I don't use any frameworks in the code right know. I would like to change that.
Doing some research, I found, that Yii turns out to be one of the best frameworks out there.
Is it possible to somehow migrate pure PHP project to Yii?
If so, then how to do this? Which steps should I follow in order to reduce the workload and enjoy the benefits the Yii framework presents?
I'm a total Yii newbie, any insights appreciated.
TL;DR : Don't do it. It's a really horrible idea.
The Rant ..
"Framework" is not a magic sauce, that you add to a project, to make it better and shinier.
Doing some research i found Yii turns out to be one of the best frameworks out there.
What a strange research you have done .. I would love to see the materials. Especially, since I would rank it as 3rd worst PHP framework. Only surpassed in it's awfulness by CodeIgniter and CakePHP.
And the reason for it is the extremely bad quality of code, that this framework displays, combined with the bad practices, that it perpetuates.
Why avoid migration?
From your description is obvious, that you are NOT familiar with this framework and have no previous experience with it.
In management of projects there a subject: risk management. And in this case, adding a previously unused framework in final stages of project would constitute a high probability an high impact risk which also, due to the sage of project, is completely unmitigated.
It means that there is a really good chance that something will go wrong. And when it does, it most likely will sink the project. Or at least push back the release data by significant length of time.
In a perfect world frameworks are used to simplify the repetitive tasks of development, at the cost of some performance. Those are the tasks you do at the start of the project. You are not at the start of a project. This means that you will gain no benefits from this "maneuver".
Why not Yii?
As I noted before, there are also reasons not only for avoiding adding framework to an existing project, but also reasons why to avoid Yii in particular.
The inheritance nightmare
All your controller will extend class CController, which extends CBaseController, which extends CComponent
All your "models" will extend ether CActiveRecord or CFormModel, which extends CModel, which extends CComponent.
Both of there chains contain static variables and execute static methods on multitude of different other classes. Combination of these factors will make debugging extremely difficult and tedious.
Global state
There are several forms of global state. One that people in PHP usually know are global variables. But that is not the only form. Every time you have a class that contains a static variable, it also creates a global state, that can (and almost always - will) cause seemingly unrelated instance mysteriously interact.
Use of global state is a core mechanic. You will see static calls all over the codebase, and the Yii's configuration file would not function without global state.
And every time you call Yii::app() you are accessing and/or changing it.
This makes unittesting impossible for Yii applications. And debugging turns into exercise of using grep on your whole project.
Tight coupling
When you create an application in Yii. It becomes bound to it. You cannot execute parts of your application without launching the full framework. Mostly it is due to the static call, that you end up adding to your code.
Every time you add a static call in your own code, that piece of code becomes tied to the name of the class. That essentially is tight coupling.
As you might have noticed (hopefully), there is another way how to achieve the same effect - the use of new operator. That is another way of coupling some code of yours to a specific name of a class.
No interfaces .. none .. whatsoever
No matter how horrible the configuration of a Yii project is, the configuration file was a well intended gesture. The least harmful way to introduce external code and replace existing components in so messed up codebase.
But unfortunately it brings in the focus the problems caused by lack of interfaces and the existing coupling.
One of the component that developers will try to replace is the CUrlManager. Mostly due to way how you can pass additional parameters.
An interface in OOP specifies the contract between two instances. It lets you define the capabilities of an instance, the methods that can be used by others. When it's not there, in a large codebase, you are left guessing, which methods are required and which are not.
In case of Yii components the problem is compounded even further due to static call and deep inheritance. The above mentioned CUrlManager extends CApplicationComponent, which extends CComponent. Also the same file defines CUrlRule and CBaseUrlRule classes.
When you are writing a replacement, you have to write some code, plug it in the configuration and then test it by running your applications. That way you know which method (or parameter) next you need to add.
Basically, it's the "save-an-see-what-blows-up" method of development.
That's not MVC!
Yii does not implement MVC or any of MVC-inspired design patterns. What it calls "MVC" could be described as ActiveRecord-Template-Logic pattern.
Instead of having proper model layer (yes, it should be a layer), the creator(s) of Yii opted for collection of active record and form wrappers. This forces the application logic to be forced in the "controllers".
On the other hand you have glorified templates, instead of proper view instances for containing presentation logic. It is somewhat mitigated by use of widgets, but those instead suffer from SRP violations, because widgets are forced to contain bits of presentation logic and perform partial rendering. The rest of presentation logic ends up again in the controllers.
And to make it all worse, the "controllers" also have to deal with authorization. This usually will mean, that whenever you change the access scheme, you will have to go through every single instance of CController to check whether it needs to be changed too.
It's not MVC. It's a mess with names taken from MVC design pattern and slapped on some components.
All the small things ..
The framework also comes with few minor issue, that do not deserve a separate section:
Defining more then one class per file:
This will get annoying quite fast, because there will be classes that are shoehorned at the class files with completely unrelated filenames. This will mean, that debugging will quite often require use of search.
Slapped on "modules":
By the looks of it, the modules where added to the framework after the fact. Which is why, when you need to set default module, you will have to set it in the configuration files parameter, that is called 'defaultController'.
I actually recently converted a MVC pattern website I had built from the ground up into Yii. It did take some time to set it all up but in all honesty it was well worth it. I was able to throw away a lot of code because there were already Yii extensions doing what I needed. I would also suggest that you keep your database because you can create the controllers and Models using Gii which will save you a ton of time.
I don't know of any quick solutions to this. It depends upon how the code was written. You have the database and your views so it is not really a complete new project when you take into yii. Yii will generate the database models for you. You already have the views from the existing project. Write the controller and actions and modify the views if necessary.
try these links as they refer to the same problem.
How do you convert an old oop project into Yii
tips on migrating an existing site to Yii
Drupal to Yii Migration
Since you already have a code in mvc, things will be much easier for you to migrate. However, while migrating to Yii, since it can generate controller and model very easily using gii, you can take the advantage of it.
So, first generate controller and model using gii, then you can replace your existing code (by replace I mean, substitute your code to the specific function in the controller and model) to the built in controller and model so that the functionality of your site still works. You can modify your view accordingly. But that won't be much of a work.
You can simply register your script for ajax, jquery and css. Those will work as well.
And yes, Yii is the best framework out there so take as much benefit as you can.
Thanks,
Ujjwal
In this project you converted php to yii framework. Its really easy for you if you do following step.
Since you already have a code in mvc, things will be much easier for you to migrate. However, while migrating to Yii, since it can generate controller and model very easily using gii, you can take the advantage of it.
second, If your database is accurate then 50% work complete.when you create CRUD operation using gii then automatically model-view-controller create.if you create mvc in php then it benifit for you.
third,You can simply include your script for ajax, jquery and css. Those will work as well you create a folder in themes(CSS,JS,AZAX,BOOTSTRAP).
four-Protected->view->layout, where you can change your theme..thats all
you also help www.yiiframework.com/doc-2.0/guide-intro-yii.html
if you think my answer is help you then rating me...thank you.
My problem is actually not the ajax loading itself, more the capability to load it without javascript. I mean, I cope easily when I code my whole project just based on ajax-availability OR just without the use of ajax.
//EDIT: Although Arend already had a more or less valid answer, at the same time 'there is no direct answer to this question'. However, I'd like to see some other approaches of developers for scenarios like mine though! Even just a few links can help!
Basically I just get frustrated, coding everything twice on the same page to make sure that both users without and with Javascript enabled have the same experience. It's annoying and I was always wondering how others solve this problem.
When I update for example two divs with dependency on the same variables, it gets messy. Here's an example:
non-js-version
require 'classobject.class.php';
$another_var = 'something';
$class = new classobject($_POST['variable']); // just an example to show that this is dynamic - I'm aware of injection!
$function = $class->returnsth(); // returns 1
if(isset($_POST)) {
echo '<div id="one">Module 1 says:'; $require 'module_one.php'; echo '</div>';
echo '<br /><br />';
echo '<div id="two">Module 2 says:'; $require 'module_two.php'; echo '</div>';
}
Now in module_two.php and module_two.php I have code that executes differently depending on the return variable of $function.
Like:
if($function >= 1 && another_var != 'something') {
// do stuff
}
else {
// do other stuff
}
Now as this works easily with a reload, when I want to load the two modules on keyUp/enter/submit or whatever, I have basically a few problems:
I have to send the $_POST variables manually to the modules to use them
I have to re-execute the class & it's methods and make a link (require_once) to them in each of the module-files.
As $another_var is not existent in the modules, I'd have to send this variable to each modules, too (with post for example) and then before it can be used, I'd have to 'change' it like $another_var = $_POST['another_var'];
I find this mildly annoying and I wonder how you guys do that. I hope my way of coding is not too silly, but I can't think of another way. It's probably hard to relate to my very basic example, but to bring a whole project with the code would be too much. To sum it up, I'm looking for a better way to code and clean this mess up - there must be a way! I thought about sessions, but for compatability I don't want to rely on them either (if someone doesn't allow cookies).
In case you can't relate to what I'm trying to accomplish with that way of having my code assembled, I'll explain a scenario I'm facing quite a lot (not important if you already understand my misery):
Basically I have my index.php page where everything gets executed, with the html body and css styling and so on. This page expects some variables, that get set from the page that requires the index (like $another_var in my example).
Now other variables can get set too (from a form for example). Depending on that different classes and methods load new variables (arrays) that get used in while-loops in my modules to echo everything out.
Hope that's not too abstract. Think of a booking system where some variables are set from the page you are coming from (the event you want to book) and then a few more things get set by the user (a timespan, some preferences,...). In the end it's supposed to show results from the database all the way to the end-result - you can say the user narrows the results from step to step.
There is no direct answer to your question, but there is some food for thought.
Seperation of concerns
You can think about if you can perhaps seperate your buisness logic and layout logic. Often the use of a template engine can help greatly with that. I've had positive experiences with for example Twig or Smarty (was some time ago, not sure how they measure up right now). It requires you to write your code in a (less linear) way, but more logical.
A typical example of an OOP like seperation of concerns might be something like this:
$this->setParam('Myparam','myvalue');
if ($this->isAjax())
{
$this->setTemplate('ajax.php');
$this->setLayout(false);
} else {
$this->setTemplate('normal.php');
$this->setLayout('Mylayout');
}
return $this->render();
It is an imaginative situation, which can be found in many MVC like applications and frameworks. The main idea is that you should have the possibility to seperate your layout from your data. I would suggest looking at some of the modern frameworks for inspiration (like symfony, codeigniter, zend framework).
Glossary / Often applied concepts in a decoupled PHP application
Here is a quick list of concepts that can be used.
Example mvc in php: http://www.phpro.org/tutorials/Model-View-Controller-MVC.html
Note: I don't really like the implementation. I much more prefer the existing frameworks. I do like the explanation in total of this tutorial. E.g. for me this link is for learning, not for implementing.
Silex
For a simple decoupled php micro-framework I would really recommend silex, by the makes of symfony2. It's easy to implement, and to learn, but contains mainy of the concepts described here; and uses all the php 5.3+ goodies such as namespacing and closures.
see: http://silex.sensiolabs.org/
Frontcontroller Pattern
Only have one, and one only point of entry for your code. I usually only have one, and one only point in your application. Usually a frontcontroller 'dispatches' the request to the rest of the application
http://en.wikipedia.org/wiki/Front_Controller_pattern
Routing
A routing system is often used in combination with the frontcontroller pattern. It basically describes which URL is connected to which module / controller. This allows you to change the way people access your app without changing the urls.
See: https://stackoverflow.com/questions/115629/simplest-php-routing-framework
Controller
A controller is the place where buisness logic is applied. Getting the data from the database, checking privileges, setting the template, setting the layout, etc. (although this is also moved outside the controller if it becomes too big of a seperate concern).
Model
The model basically is the layer in which use manage your database. This can be a simple class where you move all your mysql_* functions, or it can be a full-featured ORM. The main philosphy is that all the logic related to fetching and placing information in the database is seperated.
One step up: ORM
An often used method in applications are Object Relational Models, these 'map' SQL records to PHP objects. Doctrine and Propel are two of these well worked out libraries. I heavily rely on these systems in my development. In this sense, the doctrine or propel part will represent the model layer.
Doctrine: http://www.doctrine-project.org/
Propel: http://www.propelorm.org/
Other ORMS: Good PHP ORM Library?
PHP ORMs: Doctrine vs. Propel
View:
The view usually consists of a templating engine. Some use plain PHP as a template, others, such as symfony create a seperate scope in which variables are placed. There are many discussions and opinions about what is best, one is right here on stackoverflow:
Why should I use templating system in PHP?
PHP vs template engine
Ones I like:
- Twig: http://twig.sensiolabs.org/
- sfTemplate: http://components.symfony-project.org/templating/
- Smarty: http://components.symfony-project.org/templating/
Decoupling mechanisms:
Event based systems
Using events in your can help to seperate the code. For example if you want to send an email after a record has been saved, events are a good solution to do that; in general the model should not have to know about email. Thus events are a way to connect them: you can let your -email-send-class listen to certain records in order for them to send the right email. (Perhaps you'd rather want your e-mails send from your controller, this is probably a matter of taste).
Dependency injection
When using OOP code in PHP many relied on having singleton classes running around (configuration, etc). From an OOP point of view, this can be considered bad, because it's hard to test it, and it's not considered very elegant to have dependencies running around like that. Dependency Injection is a pattern that came form Java and is now used in the newer frameworks to get around this. It might be a bit difficult to wrap your head around, but you will see it coming back in several new frameworks.
Dependency injection in php: Dependency Injection in PHP 5.3
Frameworks:
A lot of these methods are difficult, or a lot of work to implement yourself. Many will reside to a framework for this. You may or may not need a framework. You may, or may not want to you a framework, it's your choice. But it's still useful to learn how the frameworks do it, and not try to reinvent the wheel yourself.
The no-framework php frameworks: https://stackoverflow.com/questions/694929/whats-your-no-framework-php-framework
Good habits: https://stackoverflow.com/questions/694246/how-is-php-done-the-right-way
Frameworks worth looking at (imho): CodeIgniter, Kahona, CakePHP, Symfony (1.4/2.0), Silex, Zend Franework, Yii. There are many many more, each with their dedicated fans and haters.
I wrote something like this with PHP. I already had abstracted the rendering of every page such that I define a $content variable and then require('layout.php'). The $content variable is just a big HTML string.
I wrote a PHP function to determine if request was AJAX or not.
The non-AJAX responses render the layout with $content in the middle, b/t header and footer layout content.
AJAX requests basically get this: json_encode(Array("content"=>$content)). And I use jQuery to get the HTML out of the JSON response and modify the DOM. Using json_encode() will handle escaping the string for javascript.
In the end, I effectively have AJAXified every page w/o over-engineering a complex solution.
Any browser that supports AJAX can also open a link in a new tab/window to simulate the non-AJAX request. (Or bookmark/share a link, too.)