I am trying to override
get('security.context')->getToken()->getUser(); function
Currently I am upgrading an outdated symfony 2 codebase from php5 to php7, database mongo.
The system has 3 User classes
User, Staff and Visitor
Staff and Visitor extend User.
And this function used to magically load the relevant class (Staff or Visitor)
get('security.context')->getToken()->getUser();
The User class used to have these annotations
* #MongoDB\InheritanceType("SINGLE_COLLECTION")
* #MongoDB\DiscriminatorMap({"visitor"="Ibtikar\VisitorBundle\Document\Visitor", "staff"="Ibtikar\BackendBundle\Document\Staff"})
Which generated problems and was resolved by replacing it with
* #MongoDB\InheritanceType("COLLECTION_PER_CLASS")
And after that I ran db.collection.aggregate to produce the separate collections
Now I cannot reproduce the desired result for the codebase to run smoothly, what I am trying to do is incrementally upgrade the codebase, so rather than replace the "deprecated" security context, I would like to simply override the getUser() function to check which Object to return.
Related
I am using DarkaOnLine/L5-Swagger package for project. Here is example annotation
/**
* #OA\Post(
* //annotations etc..
* )
*/
public function login(LoginRequest $request): JsonResponse
{
//login method
}
But using annotations in controllers complicates the code. Is there another way to do it in separate file?
Not sure it complicates things - with separate files you always have to update two different places.
Your annotations can be whereever you like as long as they are associated with structural elements (class, method, etc) so reflection can find them (means you need to create dummy classes, etc if the annotations are separate from the "real" code).
Also, those files need to be found by the bundle but I would expect you can configure multiple path to scan.
The downside for me is that you need to replicate all details, in particular type-hints and keep them in sync.
I have got the task to maintain some legacy code made in Laravel. It is using Bouncer for access control. The application has serious performance problems, which I am analyzing. It uses Nova for GUI.
When I am using the Laravel Debugbar I can see, that certain calls generate over 33.000 models of (bouncer) abilities, for generating a list of 25 real world objects. The database abilities table contains only 113 row.
Is this what I have to expect?
If not, is there a source explaining the pitfalls of using Bouncer?
The documentation and the blog posts on Bouncer, don't touch the topic.
The code has the simplest implementation of Bouncer.
use Silber\Bouncer\Database\HasRolesAndAbilities;
class User extends Authenticatable implements CanResetPassword, Auditable
{
...
use HasRolesAndAbilities;
...
}
No use of Bouncer::allow() etc.
The code also generates too may SQL calls. I the call mentioned above Laravel Debugbar reports:
152 statements were executed, 143 of which were duplicated, 9 unique.
The former programmers had used Bouncer, not only to limit the access of certain pages/models, but also to restrict the access to every field in those models. And fields of related models too.
After cleaning the code, the problem has disappeared.
We developed a modular project in Laravel 5.1. There are lots of core modules and models that use these modules. In our case, if the inserted module uses other modules, it will be related to those models dynamically.
When I remove the module from project by hand, I need to remove its dependencies from each module. We want establish relations without creating dependency between modules.
For example;
User model from account module used by other many other modules. Assume we have discussion module.
When we build a relationship for discussion model, we can reach the user of the corresponding model. However, if we establish a relationship with the user model, this project will no longer be a moduler.
We want to add dynamic functions to the user module from discussion module.
Temporarily, we add this code fragment to user module.
/**
* #return mixed
*/
public function lastAnswer() {
if( class_exists( Config::get( 'account.models.discussion' ) ) ) {
return $this->hasOne( Config::get( 'account.models.answer' ) )->latest();
}
return null;
}
If the config file has a relation, we link it, otherwise it will not be linked or we will return null.
But we want to add this dinamically from discussion module rather than account module.
If we accomplish this, whenever we add or remove the discussion module from project, it will continue to run without problem.
We tried to add laravel macroable as a trait but we could't make it work in model files. It gives scope error.
For transformers files we are able to do this but in model files it didn't work.
I have a unique requirement that I'm not sure how to handle. We are working with an underlying repository that allows for a quite a bit of flexibility with regards to parameters. The Controller services are injected as "service" objects into a "Service" Property for our controller classes and they wrap the calls to entity framework.
eg.
public UserController:ApiController{
public IUserSvc Service {get;set}
public UserController(IUserSvc service){
this.Service=service;
}
}
This part is handled by Autofac and all is well here.
Next, we have the standard GET,POST,PUT,DELETE,PATCH methods in the controller that accept a SINGLE user model. In other words, there is only ONE user model that is ever used, and therein lies the problem.
While the underlying service class just handles the passing of data back and forth, it pushes the requirement of the granular control of validation up the pipe. This isn't abnormal to me.
Given that we have a single API that uses models with validation attributes, we've run into an issue where different apps that call into the api require different types of validation. The model structure is fine. It's just that some properties, depending on "who you are" and what HTTPMethod is sent, either are or are not validated.
ex:
public class User{
public int UserID {get;set}
public string Name {get;set;}
}
Let's take 2 scenarios:
1. Basic User
2. System User
As a basic user, UserID is required for: GET, PUT,PATCH ( and technically delete too but it's not used). It is not required for POST because that would be creating their own user.
As a system user, UserID is NOT required in GET but is required in PUT, PATCH, DELETE.
So I am having a hard time trying to figure out how to do this without making one api for Basic User with their own models and one for System User.
I wanted to keep this high in the pipe so I wasn't doing this in the controller api methods, i.e. Check roles/claims, create/cast/or otherwise map bound model to specific concrete model per role/claim and then run validation and THEN return model binding errors if any. That's a lot of gunk in the method and I would prefer this to be on an attribute of the method or api controller.
Is there any way to do a type of model binding and or model validation based on "who you are"? That could be by role or claim?
I'm a little confused about calls I see to Mage::getSingleton, and I'm hoping someone can help me understand a little better.
I have seen a piece of core code that does this:
Mage::getSingleton('customer/session')->isLoggedIn()
I don't know PHP, but I think I can make a safe assumption from the getSingleton method name that there will be only one instance of the class specified (the class being specified as a grouped class name, and resolving to app/code/core/Mage/Customer/Model/Session.php - containing class Mage_Customer_Model_Session.
Question 1 -
How did the getSingleton method know to look in the Model folder for the class?
Question 2 -
So there is one instance of the class for the whole ... I want to say JVM as I am from a Java background, but I'll say PHP engine in the hope that that is vaguely the correct terminology; the Mage_Customer_Model_Session is not passed in a customer id or any such identifier, yet we call the method isLoggedIn()! Give there is not a Mage_Customer_Model_Session instance per customer, how can we ask a singleton if a customer is logged in when we do not tell it what customer we are talking about?
Question 3 -
I've seen calls to Mage::getSingleton('core/session') and to Mage::getSingleton('customer/session') - what is the difference?
Thank you for any help.
First, before we get to Magento, it's important to understand that PHP has a radically different process model than Java. A PHP singleton (regardless of Magento's involvement) is a single instance of a class per HTTP Request. A PHP program isn't persistent in memory the same way a Java program is, so adjust your expectations of a "singleton" accordingly.
Next, it's important to understand that Magento is a framework built on top of PHP, using PHP, and in many cases the original Magento developers wanted to push things towards a more Java like architecture. So, you're going to see things that look familiar, are familiar, but likely differ in some major way from what you're used to because they still need to hew to PHP's version of the universe.
Magento uses a factory pattern to instantiate Helpers, Blocks, and "Model" classes. The string
core/session
is a class alias. This alias is used to lookup a class name in Magento's configuration. In short, this string is converted into path expressions that search Magento's configuration files to derive a classname, based on the context (helper, block, model) it was called in. For a longer version, see my Magento's Class Instantiation Autoload article.
The concept of a "Model" is a little fuzzy in Magento. In some cases models are used as domain, or service models. In other cases they're used as a more traditional middleware database persistence models. After working with the system for a few years, I think the safest way to think about Models is they're Magento's attempt to do away with direct class instantiation.
There's two ways to instantiate a model class.
Mage::getModel('groupname/classname');
Mage::getSingleton('groupname/classname');
The first form will get you a new class instance. The second form will get you a singleton class instance. This particular Magento abstraction allows you to create a singleton out of any Magento model class, but only if you stick to Magento's instantiation methods. That is, if you call
Mage::getSingleton('groupname/classname');
then subsequent calls to
Mage::getSingleton('groupname/classname');
will return that singleton instance. (This is implemented with a registry pattern). However, there's nothing stopping you from directly instantiating a new instance of the class with either
$o = Mage::getModel('groupname/classname');
$o = new Mage_Groupname_Model_Classname();
Which brings us to sessions. PHP's request model, like HTTP, was originally designed to be stateless. Each request comes into the system with, and only with, information from the user. As the language (and the web) moved towards being an application platform, a system that allowed information to be persisted was introduced to replace the homegrown systems that were cropping up. This system was called sessions. PHP sessions work by exposing a super global $_SESSION array to the end-user-programmer that allow information to be stored on a per web-user basis. Sessions are implemented by setting a unique ID as a cookie on the user end, and then using that cookie as a lookup key (also standard practice for web applications)
In turn, the Magento system builds an abstraction on top of PHP's session abstraction. In Magento, you can create a "session model" that inherits from a base session class, set data members on it, and save/load those data members just as you would with a database persistence model. The difference is information is stored in the session instead of the database store. When you see
core/session
customer/session
these are two different session models, with each one storing different data. One belongs to the Mage_Core module, the other belongs to the Mage_Customer model. This systems allows modules to safely set and manipulate their own session data, without accidentally stepping on another module's toes, and provide logical class methods for manipulating that data.
Hopefully that answers the questions you asked, as well as the ones you didn't.
Magento's getSingleton is almost the same as getModel. The difference is getModel always returns a new instance of a class, and getSingleton creates a new instance of a class only once and then always returns this instance. See the Mage::getSingleton and Mage::getModel methods.
Magento knows about looking to the Model folder because of configs in the config.xml file (f.e. Mage/Customer/etc/config.xml). See the Magento wiki for developers to know more about config files.
You do not specify customer directly. It's done automatically by Magento in parent classes of Mage_Customer_Model_Session (see Mage_Core_Model_Session_Abstract_Varien::start() method)
Magento has not one session class to discriminate session data. For example, customer ID is stored in Mage_Customer_Model_Session and error flash message 'Product is not available' will be stored in the Mage_Catalog_Model_Session class.