ZF2 Configuration Injection Or NOT? - configuration

I've googled a lot and read as much as I can on the subject but I cannot find a direct answer to my question anywhere including here. My ZF2 application consists of roughly 7 different modules. 5 of the modules will need access to the same database configuration. The application itself has a database with roughly 124 different tables. So the idea here is to find the proper solution to write the least amount of code considering the setup.
What I'm trying to do is create a specific class to interface with the DB. Where the business logic is kept in the Module and note the controllers to keep everything more abstract and easier to maintain. By that I mean controller X should be able to create a new instance of for instance (Application\Model\DBInterface) and use the models functions to do inserts deletes updates joins selects and so forth. The reason I would like to do it this way is so that all modules installed can use the same interface without having to write endless DI statements everywhere. So what I will need is an example of how I can get the configuration for the DB (currently inside module.config.php + local.php(username / pw)) to be passed to the Application\Model\DBInterface dbConfig variable, and perhaps even an instance of the dbAdapter initialized from config if possible.
Alternatively I could potentially grab the configuration from the Application\Model\DBInterface if such a way exists.
If neither of the above is possible then I can always go back to the old way of doing things by reading an ini file for the db details and instantiating my db adapter that way.
Please keep in mind that I won't be injecting anything in the controllers as the controllers just use $db = new \Application\Model\DBInterface() so injecting into the controllers doesn't make much sense at all.
Is there a better way to do this / optimized / am I doing it completely wrong? Anyone able to share some details please. I've spent way too much time on this already and definitely need help.

Okay, so #Ocramius did just let me know what my misconception with the initializers was and helped me out a bit in understanding it. So here is a probably working solution to your Problem. My understanding about your problem is:
"How to get a DbAdapter set for all your Models implementing a DbInterface". This is how you'd do it:
Step 1: Create invokables for all classes implementing the DbInterface. Create a factory for the default Zend\Db\Adapter\Adapter and then create an initializer for your DbInterface
Module.php getServiceConfig()
return array(
'invokables' => array(
'application-model-one' => 'Application\Model\One',
'application-model-two' => 'Application\Model\Two'
),
'factories' => array(
'Zend\Db\Adapter\Adapter' => 'Zend\Db\Adapter\AdapterServiceFactory'
),
'initializers' => array(
'DbInterfaceInitializer' => function($instance, $sm) {
if ($instance instanceof \Application\Model\DBInterface) {
$instance->setDbAdapter($sm->get('Zend\Db\Adapter\Adapter'));
}
},
)
)
The Zend\Db\Adapter\Adapter is using the top-level-configuration-array-key 'db' to automatically inject the dbParams
Step 2: Create your classes implementing your Interface
Application\Model(One|Two|N).php
namespace Application\Model;
class One implements DbInterface, \Zend\Db\Adapter\AdapterAwareInterface
{
/**
* #var \Zend\Db\Adapter\Adapter $dbAdapter
*/
protected $dbAdapter;
public function setDbAdapter(\Zend\Db\Adapter\Adapter $dbAdapter) {
$this->dbAdapter = $dbAdapter;
}
public function getDbAdapter() {
return $this->dbAdapter;
}
// More of your business logic or data here
}
Step 3: Access those classes with the ServiceLocator from your Controllers
SomeController.php someAction()
$dbOne = $this->getServiceLocator()->get('application-model-one');
$dbTwo = $this->getServiceLocator()->get('application-model-two');
// Adapter will automatically be injected
When accessing the invokable from the ServiceManager the initializer will be called. The initializer then will automatically call the Zend\Db\Adapter\Adapter, which in turn get's the parameters from the configuration key 'db'
You may get more information from once the tutorial Application as well as the blog of
samsonasik: ServiceManager Cheat-Sheet

Related

need help withself reference loop when serialize linq

I know this question was asked before but I couldn't find any solution for my issue.
I am developing a WebAPI with more than 10 Controllers which their methods access a server DB.
I am using Linq2SQL to write the queries and using Json to serialize the return to send it back to my application.
The problem is no matter how simple is the query it returns the self reference loop when serialize and this is happening in all controller methods. See one example below:
var retitems = dtcxapi.ListItems.AsQueryable()
.Where(i => i.IsActive == true && i.ListName.ToLower() == listName.ToLower()).ToList();
where dtcxapi is my DataContext and ListItems is my table.
When serialize it shows: Self referencing loop detected with type 'BV.IMSWEBAPI.User'. Path '[0].User1.Users1'.
But as I said this error will occur for any query in any controller methods. I tried already to use the ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore in mWeb config but it didn't fix.
Any help will be really appreciated.
Thanks
The only true way to fix this is to not return your Linq objects and instead return a DTO/Model that is not tied to your database. If you are returning your database objects, you will always run into self referencing loops because of Navigation properties.
You haven't mentioned if you are using .NET Core or .NET Framework, but if it's Core, it won't use web.config at all and instead you should modify your startup method :
services.AddControllers().AddNewtonsoftJson(x => x.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore);
But again, this is a bandaid, the correct solution is to use DTOs
More info : https://dotnetcoretutorials.com/2020/03/15/fixing-json-self-referencing-loop-exceptions/

Replace Yii2 core class

I am looking to override the default Model \yii\base\Model class with an extended version I have created. For arguments sake lets say I have it in backend\components\Model
I have tried putting both of these in the bootstrap config file but nothing changes - it continues to use the old class
Yii::$container->set('yii\base\Model', 'backend\components\Model');
Yii::$classMap['yii\base\Model'] = 'backend\components\Model';
and within the backend\Model file:
<?php
namespace backend\components;
use Yii;
use yii\base\InvalidConfigException;
use yii\base\UserException;
use yii\helpers\ArrayHelper;
class Model extends \yii\base\Model
{
/**
* Adds a new error to the specified attribute.
* #param string $attribute attribute name
* #param string $key attribute index
* #param string $error new error message
*/
public function addCustomError($attribute, $key, $error = '')
{
$this->_errors[$attribute][$key][] = $error;
}
}
I have also tried adding it to the config file using:
'container' => [
'definitions' => [
'yii\base\model'=>
['class'=>'backend\components\model']
]
],
No matter what I do - when I create a new ActiveRecord, it still holds the same yii\base\model class.
I have spent the better half of the afternoon trying to solve this and have gone through both the Yii documentation as well as the questions already on StackOverflow. There seems to be a recurring theme of the Container function not working and people transitioning to the ClassMap function - yet neither seem to work.
Thanks for the help.
Overriding by container works if you use container to instantiate overridden class (like Yii::$container->get('yii\base\Model');). If you have class MyModel extends \yii\base\Model you're NOT using container, yii\base\Model will be used as base class no matter what, because this is how PHP works and framework has no way to change that. If you want to do this you have at least 4 options:
Preferable: just use class MyModel extends \backend\components\Model for your models and avoid hacky class replacing.
Desperate 1: copy vendor/yiisoft/yii2/base/Model.php to overridden/Model.php, alter its source code, and override autoloading config to use overridden/Model.php for yii\base\Model - add:
Yii::$classMap['yii\base\Model'] = __DIR__ . '/../overridden/Model.php';
or
require __DIR__ . '/../overridden/Model.php';
after
require __DIR__ . '/../vendor/autoload.php';
require __DIR__ . '/../vendor/yiisoft/yii2/Yii.php
You need to sync all changes from vendor/yiisoft/yii2/base/Model.php to your copy after framework update. In general this should be last resort, since it is really easy to forget about it and get completely unexpected behavior.
Desperate 2: patch vendor/yiisoft/yii2/base/Model.php directly using cweagans/composer-patches. This is easier to maintain than second option, but it still may be surprising after some time. Also, at some point your patch may get conflicts after framework update and someone that knows what is happening will need to take a look at this.
Desperate 3: fork yiisoft/yii2 and do whatever you want - it is your framework now. It may be quite useful for large and active project, but in other case you may end up with completely outdated framework, because nobody cares to fetch changes from upstream.

Yii model relationship, how is it important?

It is my first time to use yii and unlike my old programming style, i notice that it use relationship automatically in its model.
public function relations()
{
return array(
'author'=>array(self::BELONGS_TO, 'User', 'author_id'),
'categories'=>array(self::MANY_MANY, 'Category',
'tbl_post_category(post_id, category_id)'),
);
}
I'm not used in doing this MySQL relationship. my old programming habit is connecting/manipulating the data to the php program itself.. To clarify my question, is this yii model relationship important? if i dont use this method, will i encounter problems?
Yii relations are very useful and if you work with it you will see that it will make you do less coding and make your code more readable.
while it is so much used in Yii applications, if you don't use relations, you won't get into any trouble, it is supposed to help you code and develop faster.
like if you looked at Yii blog, you have relation between Post model and Comments model, and you could go like this:
$post = Post::model()->findByPk( $id ); // find one post
$allCommentsRelated = $post->comments; // just one line for all search query and instanciating models
BTW in relations, there are two type of loading:
lazy loading (this is default mechanism)
eager loading
you have to know your scenario, and choose one that suites that scenario best

should the builder reset its build environment after delivering the product

I am implementing a builder where in the deliverable is retrieved by calling Builder::getProduct() . The director asks various parts to build Builder::buildPartA() , Builder::buildPartB() etc. in order to completely build the product.
My question is, once the product is delivered by the Builder by calling Builder::getProduct(), should it reset its environment (Builder::partA = NULL;, Builder::partB = NULL;) so that it is ready to build another product? (with same or different configuration?)
I ask this as I am using PHP wherein the objects are by default passed by reference (nope, I don't want to clone them, as one of their field is a Resource) . However, even if you think from a language agnostic point of view, should the Builder reset its build environment ? If your answer is 'it depends on the case' what use cases would justify reseting the environment (and other way round) ?
For the sake of providing code sample here's my Builder::gerProcessor() which shows what I mean by reseting the environment
/**
* #see IBuilder::getProessor()
*/
public function getProcessor()
{
if($this->_processor == NULL) {
throw new LogicException('Processor not yet built!');
} else {
$retval = $this->_processor;
$this->_product = NULL, $this->_processor = NULL;
}
return $retval;
}
Resetting the state in getProcessor() is non-obvious and if you want to do that the method should reflect that in it's name, e.g. getProcessorAndReset(). A cleaner solution would be to just give the builder a separate reset() method.
In general, your getProcessor() should not reset it's internal state because methods should not magically change behavior but reliably do the same. getProcessor() is a query and that query should return the same configured Processor on each call. It should not change state. Resetting the state is a command. You want to separate command and query methods.

Doctrine2 Best Practice, Should Entities use Services?

I asked a similar question a while back: Using the Data Mapper Pattern, Should the Entities (Domain Objects) know about the Mapper? However, it was generic and I'm really interested in how to accomplish a few things with Doctrine2 specifically.
Here's a simple example model: Each Thing can have a Vote from a User, a User may cast more than one Vote but only the last Vote counts. Because other data (Msssage, etc) is related to the Vote, when the second Vote is placed the original Vote can't just be updated, it needs to be replaced.
Currently Thing has this function:
public function addVote($vote)
{
$vote->entity = $this;
}
And Vote takes care of setting up the relationship:
public function setThing(Model_Thing $thing)
{
$this->thing = $thing;
$thing->votes[] = $this;
}
It seems to me that ensuring a User only has the last Vote counted is something the Thing should ensure, and not some service layer.
So to keep that in the Model, the new Thing function:
public function addVote($vote)
{
foreach($this->votes as $v){
if($v->user === $vote->user){
//remove vote
}
}
$vote->entity = $this;
}
So how do I remove the Vote from within the Domain Model? Should I relax Vote::setThing() to accept a NULL? Should I involve some kind of service layer that Thing can use to remove the vote? Once the votes start accumulating, that foreach is going to be slow - should a service layer be used to allow Thing to search for a Vote without having to load the entire collection?
I'm definitely leaning toward using a light service layer; however, is there a better way to handle this type of thing with Doctrine2, or am I heading in the right direction?
I vote for the service layer. I've often struggled with trying to add as much logic on the Entity itself, and simply frustrated myself. Without access to the EntityManager, you're simply not able to perform query logic, and you'll find yourself using a lot of O(n) operations or lazy-loading entire relationship sets when you only need a few records (which is super lame when compared to all the advantages DQL offers).
If you need some assistance getting over the idea that the Anemic Domain Model is always an anti-pattern, see this presentation by Matthew Weier O'Phinney or this question.
And while I could be misinterpreting the terminology, I'm not completely convinced that Entities have to be the only objects allowed in your Domain Model. I would easily consider that the sum of Entity objects and their Services constitutes the Model. I think the anti-pattern arises when you end up writing a service layer that pays little to no attention to separation of concerns.
I've often flirted with the idea of having all my entity objects proxy some methods to the service layer:
public function addVote($vote)
{
$this->_service->addVoteToThing($vote, $thing);
}
However, since Doctrine does not have any kind callback event system on object hydration, I haven't found an elegant way to inject the service object.
My advice would be to put all the query logic into an EntityRepository and then make an interface out of it sort of like:
class BlogPostRepository extends EntityRepository implements IBlogPostRepository {}
that way you can use the interface in your unit-tests for the service objects and no dependency on the EntityManager is required.