Tin Can PHP library: Person object - php

My question relates to the Tin Can PHP API library's Person object and what use may be made of it.
The library's Person object is (so far as I understand) an implementation of the Agents Resource in Part 3 Section 2.4 of the xAPI specification (link: https://github.com/adlnet/xAPI-Spec/blob/master/xAPI-Communication.md#24-agents-resource). The specification recognises a Person object and indicates that the purpose of the object is to
provide combined information about an Agent derived from an outside
service, such as a directory service
It seems from that description, and from the developers of the library (see link), that the specification's Person object is intended to provide a means of collecting, within the one object, information about a person which is dispersed among a number of different Agent objects.
I have had difficulty following the examples in the library but the following (oversimplified) code seems to work in the SCORM Cloud LRS:
...
$agent1 = new TinCan\Agent();
$agent1
->setMbox('david.jones#somehospital.gov.au')
->setName('Dr David Jones');
$agent2 = new TinCan\Agent();
$agent2
->setMbox('d.jones#medicalorg.org.au')
->setName('David Jones');
$person = new TinCan\Person();
$person
->setMbox([$agent1->getMbox(), $agent2->getMbox()])
->setName([$agent1->getName(), $agent2->getName()]);
...
Is the library's Person object intended to be saved to the LRS? If so I have not been able to find any means of doing so using the library's Statement object. If not, what is its intended use?
I would be grateful for clarification. Thank you.

The API does not provide a means to save this object. It is intended for the LRS to use whatever means it can to assemble multiple Agents that represent the same entity into the Person object. The intended purpose is to allow systems accessing the statement stream to be able to combine those streams for multiple Agents to get a fuller picture of that person's overall activity.
For example, I may have 3 (or X) identifiers that represent me as a person, let's assume they are:
mailto:dave.personal#example.com
mailto:davelastname#work.example.com
{"name": "#dave11785","homePage": "https://twitter.com"}
Passing any one of those Agent identifiers (as a full Agent representation) to the Person read only resource will return a Person object that includes all of them assuming sufficient knowledge by the LRS to map them together. For a reporting system therefore, it would be possible while it is reading the statement stream to request the Person object for each new Agent it sees and then coordinate statements with disparate actor properties (for instance) into a single record of that person's complete activity. The key here is that the LRS has to have been developed (or integrated) in such a manner that it has the requisite knowledge to associate Agents together.
TinCanPHP provides the full range of data model objects because in theory it could be used to write an LRS just as much as to communicate with one as an LRP. The key implementation detail here is that it provides the GET /agents readonly resource via the TinCan\RemoteLRS class which will provide back a TinCan\Person object. Since your code is not interacting with an instance of the TinCan\RemoteLRS class it isn't actually communicating with the LRS so SCORM Cloud's LRS is irrelevant in this case. If you were to interact using the available resource you would get a Person object returned that includes only the Agent you passed into it because (at least at the time of writing) Cloud does not know how to associate multiple Agents, but it does know that the default is the Agent provided to it.

Related

RESTful api and related resources

I'm developing my first RESTful api, which (unfortunately) is being done on an already existing system and the idea is to allow third-parties to access this system.
Everything was fine until I realised that I have multiple ways to access the same resources. I will try to explain it using one of the parts of the system. The system has been built using Laravel 5.8 and has, among others, the following database tables:
users
emails
sms
Each user can have many emails, and each email belongs to only one user. The same applies for text messages.
I've "ignored" all the current code, because it wasn't built on a proper way to make it an RESTful api, so I've created a new folder Api and all my code is there.
I thought it would make sense to have the following endpoints
/api/v1/users
/api/v1/users/1
/api/v1/users/1/emails
/api/v1/users/1/emails/1
/api/v1/users/1/sms
/api/v1/users/1/sms/1
In this way I can have a list of users, get all the details of a user, get a list of emails/text messages and also get all the details of a specific email/text message. However, one of the requirements is to have a page with a list of emails/text messages, so it's starting to make sense to have:
/api/v1/emails
/api/v1/emails/1
/api/v1/sms
/api/v1/sms/1
To avoid having 2 endpoints to get the same resource (/api/v1/users/1/emails/1 and /api/v1/emails/1 will return the email with id 1) I'm considering to get rid of the deep endpoints /api/v1/users/1/emails and change them to something like /api/v1/emails?user_id=1.
Is this against RESTful principles? I couldn't reach a conclusion on my research about having 2 endpoints to access the same resource, but it doesn't "feel" right. On the other hand, having /api/v1/emails?user_id=1 may rise some security/privacy concerns (for example, I need to make sure that user 1 can only access /api/v1/emails?user_id=1 and not /api/v1/emails?user_id=2), but seems more flexible because I can use it alone to get all the resources or with the user_id filter to get only specific resources.
Is there a convention for this case?
It may help to review how we understand "resources" in a REST context.
Any information that can be named can be a resource: a document or image, a temporal service (e.g. "today's weather in Los Angeles"), a collection of other resources, a non-virtual object (e.g. a person), and so on. In other words, any concept that might be the target of an author's hypertext reference must fit within the definition of a resource.
/api/v1/users/1/emails
/api/v1/emails?user_id=1
/66eb6757-254e-49b4-bc8a-d04330f4482e
REST treats identifiers as semantically opaque -- general purpose clients do not use the spelling of the identifier to understand what is going on. Consider a web browser - it knows that http://example.org/cat.jpg is an image not because jpg, but because img.
That means that the server may use any spelling it likes -- any information encoded into the URI itself is done at the server's discretion and for its own use.
This isn't to say that there aren't advantages to using "guessable" spellings; just that REST is completely agnostic about whether or not identifiers should be guessable.
Choosing spellings for your identifiers that make your implementation simpler is completely within bounds.

What is the best way to replace static sets of values in PHP

Statics, consts and singletons are considered a bad practice because they obstruct testing, and create a maintenance problem due to references in various places. In a mini-framework for websites, I am running into these problems and want to replace the statics, but don't know the best alternative in one use case.
This use case is illustrated by a permissions system based on groups: for a client C to have access to data item X, a group name in C's array of authorization group names must match one in X's array of "required" names.
Comparisons ("does the client have this auth?") can be easily abstracted out to a dynamic calls. But when assigning a group name to a client, or assigning a "required" group name on a data item, how can I refer to them individually and police that each is from a centrally defined set, without statics?
Current code looks like:
$client->appendAuzGroupName( Tokens::AUZ_GRP_PUBLIC );
-- with Tokens loading values from a config file at each cache refresh.
Searching here and on the web has turned up a lot of advice against static/const/singleton, but the only idea I've found on replacing them is "use IoC / DI". However, taking these values via params only moves the problem to a different place in the code.
I'm open to changing to another auth system design, but it must have this level of granularity, and listing usernames (ACL design) seems unlikely to be practical at scale.
OK I may have solved my own problem.
The class Tokens will have a public constructor, private static array for the values from XML (which is written by admin interface), public methods to retrieve them; it loads the values on instantiation iff they are not already loaded.
Some small facility to gather subsets of values from Tokens, for example the list of authorization group names, and deliver an object (of a class TokenSet or such) containing them
These 'sets of values' are passed in function calls, e.g. to give the admin interface a set of choices to be applied for each new page's 'required' permission levels.
Thus instead of directly accessing stored-in-memory values, object that needs to use them will get, as parameter, an object containing a relevant set of them. This will be testable and avoid hardcoded references that would create dependencies and maintenance issues.

PHP OO - how to initialize your business objects?

By business model, or business objects, I mean plain old objects like a "User" with all their properties name, adress, ...; in addition to all the user properties let's say each user would have an "AppointmentBook" object, each book has a set of "TimeSlot" objects, etc.
The business model has objects with references between them, at least that's how I code a business model in Java.
Here comes the question:
To intialize my business objects, in Java, I would
fetch all of the data from DB only once during application
initialization,
map data from my DB to my business objects
store in memory (maps) and they would be shared across all the requests.
PHP's Share-Nothing-Architecture is confusing me for proper OO programming:
If I use the same logic, I would have to fetch all the objects from DB, for every request (I know I could still cache, but you don't cache all of your DB, it's not a question about caching but rather about the way of programming in PHP and its architecture).
So let's say that for one HTTP request, I just need the User properties and I don't need to access his appointment book. It would be a pitty to fetch all the data from the DB for all the objects the User makes reference to, as I just need his properties. This means that I will initialize PHP objects from my model with a lot of NULL values (NULL because of the objects contained in User that I won't load) which can later on lead to errors.
I was wondering how professional PHP developers usually use their business objects?
(I'm coming from Java)
UPDATE: It was kind of stupid to say that I would load the whole database into memory during application init in Java. What I rather meant is that, if I need to fetch a specific user, I could just load all of its data and that would be accessible through all the requests.
In PHP you do not keep all the data of your domain business model in the memory. Instead you only request from DB ( though cache, if needed ), the data you want.
Model layer in php should be built from multiple domain object and data mappers ( i assume, that part is not so different from Java ). If you need User details, then you fetch only that information from database/cache. You most likely will have a separate mapper just for dealing with user(s).
You display the information about that user, and forget about the query. Next request (when and if it comes) will require different information. Maybe you will want ContactList for that User ... then you really do not need user itself, only his user_id. Again, you let you mapper to fetch data into the domain object responsible for handling contact list, and if contact list contains User instances, then just create them, but leave in "unfetched" state (object knows only own user_id). Fetch them only if you really need to, and only the parts which you will use ins that "view".
P.S. you might have notices, I told that model later should be segmented, but quite often php developers just create single class of each DB table (which implements ActiveRecord) and call it "model". This is a result caused by Ruby on Rails influence on php framework developers, which, IMHO, is one of the worst things that has happened to PHP in past 5 years.
Your Java example implies your storing your entire databases content in memory. If your doing that, what's the point of the database? Why not just create all those object and memdump them for persistence.
If I use the same logic, I would have to fetch all the objects from DB, for every request
That's simply madness, you don't need to fetch anything, you create new instances when you need them and destroy them when you no longer need them.
So let's say that for one HTTP request, I just need the User properties and I don't need to access his appointment book.
That's easy, redesign your user. Your user needs it's properties and a property called appointmentBook which is simply an array of appointment book ids.
If you actually need those appointments you can fetch them from the database later.
This means that I will initialize PHP objects from my model with a lot of NULL values (NULL because of the objects contained in User that I won't load) which can later on lead to errors.
Not really, if this is the case your User object is too big. Make it smaller, you should load the entire user. Except of course the user has to be small enough for you to sensible load it.
If you don't want that then you can always create a UserProperties class and let every User have one. When you load the User you load the properties, but you also have an option to create the properties seperately.
Even in Java you would not load all data from the database into memory. You can however - as you write - often load more compared to short Transaction Scripts you normally have in PHP.
You models should be "clever" then to only load the data from the persistence storage that is needed to perform the requested action. This requires the object to be "clever" enough to lazy-load data probably.
This can be achieved with a Domain Model that knows enough about itself and a Data Mapper that knows enough about the storage for example.
There are other patterns as well which might suit your needs depending on the type of application, however a Domain Model together with Data Mapper is quite flexible.
An exemplary data mapper in the PHP world is Doctrine.

How to deal with the 'DataSet' data structure in php?

I'm trying to do a call to a soap webservice from php.
The webservice returns an ADO.NET DataSet structure. Are there any libraries in PHP that can deal with this sort of data structures? If so, what are they called and where can I find them? If not, feel free to give tips?
So far, I have this (using ActiveMQ and the NuSoap library):
/**
* Create a new service instance
* Provide ActiveMQ uri and the extended class name
**/
$client = new Client('tcp://localhost:61613?tcpNoDelay=false', 'test');
/**
* New service reference
**/
$service = new ServiceProxy($client, 'ServiceName');
/* Service call */
$result = $service->get_clients();
get_clients() is a method that does the actual service call and it gets the DataSet structure in return. How can I manipulate this return value?
In .NET for example, there is a DataSet class. The ADO.NET DataSet contains one or more ADO.NET DataTables which in their turn consist out of one or more ADO.NET DataColumns and DataRows which are returned in a collection (array).
A simple code example, where the DataSet only contains one DataTable, can be:
/**
* Here, the val variable will contain the data positioned in the
* first field of the first DataRow of the first DataTable
**/
string val = dataset.Table[0].Rows[0].ItemArray[0];
I want to do the same in PHP, but I need a helping hand.
I would suggest you try learning more about the structure of the data you are working with. It is most likely some form of JSON or XML, which can be manipulated through the large set of PHP xml and json handling libraries.
Your first step is to look at the data being returned by your request and identifying it's format. Microsoft documents the ADO.NET API's datasets in depth HERE at the MSDN library. This should help you to make sense of what you are seeing when you inspect the data. Some data providers allow you to access the same data in different formats, depending on a parameter or a family of similar functions. Do you have documentation for your providers API?
Next, after you have identified the format and deciphered the specifics of the datasets schema, You need a class to manipulate the data. If you are dealing with something that conforms to a published standard you can use something like simpleXML, JSON or DOMXPath.This class should store the data in protected member variables and provide methods to inspect, iterate, load, refresh, search and so forth. You should refer to the PHP manual's function reference for help here and write whatever functions you need. I would write it generically to handle any similar dataset and derive a class to expose exactly the data I need for a particular application.
Another approach would be to write a COM component in a .net language to access and manipulate the data and import it's functions through PHP's COM extension. I think I would go with this choice if the data format is a weird proprietary Microsofty one.
The third possible approach works only if you have programming access to the server. If you can adapt the service provider to comply with the specification, Microsoft has released an interoperability toolkit which is supposed to act as a bridge between .net services and PHP clients using a layer of proxy objects to expose the ado.net data to PHP scripts. They throw the word RESTful around alot, but I'm not really sure what they mean by that. Check out the OData SDK for PHP HERE at Microsoft's interoperability HQ (there is info here about PHP and other Microsoft platforms and products like Azure, silverlight, Bing, etc., as well). As I said though, I think you would need the data provider to emit data which conforms to their standard. Perhaps it already does. I can't tell without a schema! If so then this is your best bet.
Good Luck!

Data Transfer Objects in PHP, lots of classes with the same contextual name

Well I just figured out that there's this DTO pattern. I wonder if
they are useful.
I mean, should I map all my domain objects to their corresponding DTO objects and assign them to view instead to the domain objects themselves? I would, then, have a lot of classes with the same contextual name.
Like:
User(Domain Object),
UserDTO,
UserMapper or UserPersistenceFactory,
UserFactory,
UserSelectionFactory,
UserUpdateFactory,
UserAssembler(for DTO mapping),
UserCollection,
UserViewHelper(maybe)
etc...
Typically a DTO can help you separate the data concerns of the database from the data concerns of the objects that make use of the data. You can place validation in the DTO to ensure that a particular member follows a specific format. In this way, that extra code doesn't clutter up the objects which don't care what the database needs.
Additionally, DTO become powerful when talking to a database indirectly. However, this is of much more importance in languages that can auto-generate DTOs.
Therein is the most powerful and compelling aspect of the DTO. That it can be auto-generated easily. This is also true in PHP, however it requires additional tools.
I see why you might want to use them in PHP, however, I must admit I've yet to see a reason to do so myself. Typically a Factory + Object is enough for most applications.
HOWEVER
In an application that has objects that don't mirror the database directly, a DTO becomes empowered again. For example: an application that has People who are comprised of lots of meta information like Addresses and Personal Info and Credit Cards, could use DTOs for all the individual data, then use a Person object to handle all the usage of that data. In this way, a Transaction could be passed the Credit Card DTO directly, with no muss and no fuss. It could then access whatever data it needs to from the card. However, as soon as you want to put an Address on that Credit Card DTO, you no longer have a strict DTO.

Categories