Warning: This page has not been updated in over over a year and may be outdated or deprecated.
videos:customizing_record_views
Differences
This shows you the differences between two versions of the page.
Next revision | Previous revision | ||
videos:customizing_record_views [2022/05/04 11:14] – created demiankatz | videos:customizing_record_views [2023/08/01 12:13] (current) – [Transcript] demiankatz | ||
---|---|---|---|
Line 15: | Line 15: | ||
===== Transcript ===== | ===== Transcript ===== | ||
- | // This is a machine-generated transcript | + | Hello, |
- | :!: Coming soon. | + | So to give a quick overview, I should first say that this is a very in-depth detailed topic, and we can only scratch the surface of it in a brief video. So I encourage you to look at the learning VuFind book, look at the code, look at the wiki, and ask questions of the community if you need more help. But I hope that this video will provide some useful context, and at least show you some of the starting points you'll need to explore to get a deep understanding of all of these concepts. |
+ | |||
+ | So in this video, we're going to talk about record drivers, which are the way VuFind internally represents individual records regardless of where they come from. We're going to talk about the record data for matter, which is a tool that VuFind uses to display tables of data taken from records, which makes it easy to customize particular parts of the user interface in sophisticated ways. And I'm going to do a quick demo of how you can add a custom field to your VuFind instance if you have something you want to display that's not part of the core system. | ||
+ | |||
+ | So let's start by talking about record drivers. What is a record driver? A record driver is an abstraction. It is a PHP object wrapped around some metadata with accompanying custom templates. And this is how VuFind displays all of the data coming from all of the records that it interacts with. | ||
+ | |||
+ | The idea here is that VuFind only interacts with data using record driver code. It does not directly interact with the data. What do I mean by that? For example, in a MARC record, the title is stored in a 245 field. But information about things like 245 fields only exists inside record driver code. Outside of the record driver, VuFind only cares about getting a title. It asks the record driver, please give me a title. And the record driver, if it's wrapped around a MARC record, gives it the 245 field. If it's wrapped around a Dublin core record, it gives it the DC title field, etc, etc. So it lets us encapsulate all of the specific metadata handling in one place and write more generic, more reusable, more flexible code that can interact with all kinds of things at a higher level. | ||
+ | |||
+ | VuFind uses what is called duck typing to determine compatibility between its various features and particular records. So for example, you know, if we want to display a title, it's going to check with the record driver if it's capable of displaying a title and then only display it if appropriate. Now, of course, everything has a title, but there are some more advanced features that are more metadata format specific. And for these purposes, the record drivers are able to conditionally provide data only when it's supported and a lot of VuFind' | ||
+ | |||
+ | Now, even though VuFind is designed to be extremely flexible and to support a lot of use cases, the most common use case in VuFind is displaying bibliographic records, records representing books or other materials. And so there is a record driver called default record which extends abstract base and adds a whole lot of methods that support bibliographic record functionality, | ||
+ | |||
+ | Record drivers have their own plug-in manager just like pretty much any extensible component of VuFind. So while the default is to use the record drivers from the VuFind record driver name space, you can very easily create your own record drivers or extend the built-in record drivers to add methods, change behavior, etc. All of this is extensible and over-rideable. It's also worth noting that the way the plug-in manager is used varies from search backend to search backend. And search backends were talked about in last month' | ||
+ | |||
+ | In many cases, this is pretty simple, a lot of the web-based discovery systems just have a single record driver. So for something like EDS or Summon, we're just going to pull a copy of the appropriate record driver out of the plug-in manager and populate it with data for every record that we've got. But for records coming from the local Solr index, we do things in a slightly more sophisticated way because it's possible that we have sort of heterogeneous data in our Solr index. We might have some MARC records populated from one place, some Dublin core records populated from another and so forth. And of course, depending on what kind of data is stored in the Solr index, we may need to display it in different ways. | ||
+ | |||
+ | And so this is where Solr's record format field comes into play. For each record that we fetch from Solr, we look at the record format field and we look to see if there is a record driver registered in the plug-in manager with the name Solr and the value of record format following that. So for example, if record format is set to MARC, we look for a Solr MARC record driver. If we find a match, we use that. If we don't find a match, we default to Solr default, which is another core record driver that provides all of its data based on what has been indexed into Solr. Some of the other drivers like Solr MARC, which I mentioned, augment the data in the Solr index with more specific things pulled directly from the raw source record. So again, that's a fair amount of detail, but the point is we have a lot of flexibility in how we load these record drivers and it lets us be very specific in what we present while interacting with the rest of the VuFind system in a very standardized and generic way. So as I mentioned at the beginning of the discussion of record drivers, the record drivers are not just PHP classes. They are also sets of templates. The reason for this is that some parts of VuFind displays are rendered using record driver specific templates. So for example, when you get a screen of search results, every individual search result that you see is getting rendered using a different template pulled from your theme. The reason for this is as I say, you might have a mix of different kinds of records in your results and they may need to be displayed very differently. So VuFind has the ability to display a totally different template for multiple records in the list based on what kind of records they are. And again, in practice, most of what VuFind does by default is very similar, but the design is such that it can be extended a great deal and you could have an extremely diverse set of displays if you need them. So the templates that are used for these types of displays are found in the record driver subdirectory of the templates directory of your theme. Inside this record driver directory, there are driver specific directories whose names match the record driver class names minus the namespaces. | ||
+ | |||
+ | So for example, if we had templates that were specific to VuFind record driver MARC, they would be in a folder called templates record driver MARC, not using the VuFind piece of the name. Again, most of VuFind' | ||
+ | |||
+ | The record data formatter is a view helper. It has a factory that builds it with default settings for VuFind. So if you look at the record data formatter factory, you will find all of the default configurations from the various places where we display tables of data. These are things like the sort of core part of the record page where we display primary data about a record areas in some of the tabs like the description tab. | ||
+ | |||
+ | The record data formatter replaces these difficult to maintain gigantic templates with configuration. Of course, with every advantage comes a disadvantage and the obvious disadvantage here is the record data formatter has a much steeper learning curve, customizing a giant HTML template is a matter of cut and paste. The act of doing it is easy. It's the maintenance that's hard and the record data formatter kind of reverses that making it harder to set things up in the first place because you have to learn more, but making the long term maintenance considerably simpler. So it's not perfect, but it's worth the investment in the long term. I think it saves many people some trouble. | ||
+ | |||
+ | So let's talk about how the record data formatter configuration works since understanding this is very important to actually making use of it. So the record data format is a view helper. It has a factory that builds it with default settings for VuFind. So if you look at the record data formatter factory, you will find all of the default configurations from the various places where we display tables of data. These are things like the sort of core part of the record page where we display primary data about a record areas in some of the tabs like the description tab. | ||
+ | |||
+ | And they were difficult to maintain and also very difficult to customize because if you wanted to change the order of two fields or add something new, you had to copy this entire huge template, customize it in your local theme. And then every time you had an upgrade to VuFind, you would have to reconcile any changes in that template with your local customizations. It was an error prone tedious process and just not very flexible. So the idea was instead of hard coding these tables into these templates, let's build a helper that takes a configuration that tells it what fields to display, how to display them, what order to display them in. And then if you want to customize something instead of copying and pasting potentially hundreds of lines of HTML and PHP, you can just adjust a configuration slightly. And thus you express your customization in a more specific and concise way, it's easier to reconcile during updates, etc. So of course that's the advantage here using the record data format or replaces these difficult to maintain gigantic templates with configuration. Of course, with every advantage comes a disadvantage and the obvious disadvantage here is the record data format has a much steeper learning curve, customizing a giant HTML template is a matter of cut and paste. The the act of doing it is easy. It's the maintenance that's hard and the record data format are kind of reverses that making it harder to set things up in the first place because you have to learn more, but making the long term maintenance considerably simpler. So it's not perfect, but it's worth the investment in the long term. I think it saves many people some trouble. So let's talk about how the record data format or configuration works since understanding this is very important to actually making use of it. So the record data format is a view helper. It has a factory that builds it with default settings for VuFind. So if you look at the record data format or factory, you will find all of the default configurations from the various places where we display tables of data. These are things like the sort of core part of the record page where we display primary data about a record areas in some of the tabs like the description tab. | ||
+ | |||
+ | Each of these areas has its own configuration established in the factory and there' | ||
+ | |||
+ | The most common ways of describing fields in this configuration are either just specifying there' | ||
+ | |||
+ | I should also note that if you use the custom template approach, it follows the same mechanism as other record driver related templates so you can potentially tell the record data format or to use a particular template to display a particular kind of value and then you can implement that template differently for each of your record drivers if you need to. Again, there' | ||
+ | |||
+ | If, for example, you need to call a single method of the record driver and have that lead to multiple labeled sections in your final display. You can get quite complex. But in the interest of demonstrating this while keeping things simple, I'm now going to dive into a demo of how to use the record data format and record drivers to add a custom field to VuFind. | ||
+ | |||
+ | So the use case for this demo is that we have a local note field in this example 597A which contains a note about a donor and we just want to create a donor note field in VuFind that shows the contents of this MARC field. And here is a sample record which we're going to be working with just to show what this looks like. As you can see, it's just a bare minimum MARC record with an author, a title, publisher, and a donor note. | ||
+ | |||
+ | So with that, I am going to switch over to my tutorial test machine. So this is the same test machine that we've been building on through all of the tutorial videos and for the purposes of this example, the key details of note are that we are using a local code module called tutorial and also a local custom theme called tutorial. Both of these were built in earlier videos so if you need to learn more about custom code or custom themes, just go back through the list, you'll find them. But I am just going to dive right in here and start building. I'll explain as I go. | ||
+ | |||
+ | So I'm going to go to the command line and I'm going to switch to the VuFind home directory. And I am actually going to also bring up my code editor since we'll be editing some files and running some commands. | ||
+ | |||
+ | So the first step in adding a custom field to VuFind is to index the data that we want to display in the field. Now as I mentioned, we do store the entire raw records in the index. So in theory, since this is a MARC file and the data is in a 597, I could just skip the indexing step, write some custom code that pulls the 597 out of the stored MARC record and be done with it. | ||
+ | |||
+ | But in general, I think it's a little more useful to pull the data into Solr because this allows you to search it. And it's also more generic if you potentially have the same type of data coming from multiple sources. If you can just index it into Solr from various formats, then you only need to write one set of code to pull the data from the Solr index. You don't have to worry about all the metadata specifics in the code you're writing. | ||
+ | |||
+ | So for this example, first thing we're going to do is index the 597A. So I'm just going to go to my local import MARC local properties file, going to go down to the bottom, and I'm just going to create a custom field called donor STR MV, which is a multivalued string field, taking advantage advantage of the dynamic field suffixes defined in VuFind Solr schema. I'm going to say donor string MV equals 597A. I'm going to save that file, then I'm going to go to the command line and I'm going to run import MARC.sh on my example MARC record to index it. This will take just a a moment. And there we go, our record, if an ID of donor example has been indexed into our VuFind. | ||
+ | |||
+ | So now if I go to the catalog and I just look that up by ID, here is our record. And if I look at the staff view, I can even see there' | ||
+ | |||
+ | So in this instance, we know that we're only going to have this donor note in our MARC records. And we just need to extend that class so we can add a method to it. And we'll do that in the tutorial module. If in a hypothetical scenario, we had multiple types of records that all needed to have this implemented, | ||
+ | |||
+ | The core default record data for matter settings are found in VuFind view helper root record data for matter factory. | ||
+ | |||
+ | I'm creating an equivalent directory structure in my tutorial module where I can extend that. | ||
+ | |||
+ | We don't currently have a code generator that is particularly well suited to overriding this kind of factory. | ||
+ | |||
+ | I'm creating record data for matter factory.php in that directory that I just built. | ||
+ | |||
+ | Here is our custom factory. | ||
+ | |||
+ | For namespace, of course, we have to match our directory structure. | ||
+ | |||
+ | So it's tutorial view helper root. | ||
+ | |||
+ | We're going to make use of that spec builder helper class for setting up the configuration. | ||
+ | |||
+ | I just have a use statement to make that code accessible here. | ||
+ | |||
+ | My class definition, my local record data for matter factory extends the core record data for matter factory. | ||
+ | |||
+ | The core record data for matter factory has a method for each of the default configurations that it manages. | ||
+ | |||
+ | There' | ||
+ | |||
+ | I want to simply add a line to that. | ||
+ | |||
+ | I create a new spec builder, which is that helper class from manipulating these configurations and I initialize it using the output of the parent version of this method. | ||
+ | |||
+ | I load the existing default core specs into the spec builder. | ||
+ | |||
+ | This takes the PHP array of settings, turns it into an object with convenience methods for manipulating things. | ||
+ | |||
+ | Next, I call spec set line, which is one of the helper methods for adding something. | ||
+ | |||
+ | Set line is the simplest option. | ||
+ | |||
+ | This just says, I want to label this donor note, and I wanted to display any or all values coming from the record drivers get donor' | ||
+ | |||
+ | My method returns a call to spec get array, which turns my spec builder object back into a PHP configuration array. | ||
+ | |||
+ | So we just take what we've already got by default, we add something to it, and we return it. | ||
+ | |||
+ | You can do other kinds of manipulations here. You can change the order of fields, you can remove fields you don't want, you can add fields in a whole variety of ways. But this is the simplest possible example. So now there' | ||
+ | |||
+ | // This is an edited version of an automated transcript. Apologies for any errors. // | ||
---- struct data ---- | ---- struct data ---- | ||
+ | properties.Page Owner : | ||
---- | ---- | ||
videos/customizing_record_views.1651662850.txt.gz · Last modified: 2022/05/04 11:14 by demiankatz