About Features Downloads Getting Started Documentation Events Support GitHub

Love VuFind®? Consider becoming a financial supporter. Your support helps build a better VuFind®!

Site Tools


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.

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
videos:customizing_record_views [2022/05/05 11:25] – [Transcript] demiankatzvideos:customizing_record_views [2023/08/01 12:13] (current) – [Transcript] demiankatz
Line 15: Line 15:
 ===== Transcript ===== ===== Transcript =====
  
-// This is a machine-generated transcript and will be corrected as time permits//+Hello, and welcome to this month's VuFind tutorial video. This month, we're going to be talking about customizing VuFind's record views.
  
-hello and welcome to this month's VuFind tutorial video +So to give a quick overview, I should first say that this is a very in-depth detailed topicand we can only scratch the surface of it in a brief video. So I encourage you to look at the learning VuFind booklook at the codelook at the wikiand ask questions of the community if you need more help. But I hope that this video will provide some useful contextand at least show you some of the starting points you'll need to explore to get a deep understanding of all of these concepts.
-this month we're going to be talking about customizing VuFinds record views +
-so to give a quick overview 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 formatter 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 mark 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 mark 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 duct 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's code is designed to +
-either load particular logic based on the presence of capabilities or +
-to gracefully degrade if we want to do something and we can'+
-all of this is designed again to make it possible to write fairly generic fairly reusable code and have it +
-interact successfully with all kinds of different data because VuFind is +
-designed to let you index practically anything and also to interact with a number of external systems that format +
-data in different ways of course with all of the possibilities that are +
-out there it would be easy to end up with a lot of redundant and complicated +
-and contradictory code but VuFind uses features of the php language particularly traits and +
-inheritance to make code as reusable as possible and +
-to share features across multiple drivers so in order to understand record drivers +
-having a good understanding of php object oriented +
-logic is helpful so let's go into a little more detail on +
-the php side of things so every record driver is a php class +
-and all of these classes can be found in the VuFind record driver namespace +
-there are a few record driver classes that are particularly important one is called abstract base this is an +
-abstract base class as the name suggests and all of the record drivers extend to +
-this class either directly or indirectly and this is where the absolute bare +
-minimum functionality for record drivers live all of the things that every record driver has to be able to do are +
-implemented here and this is fairly minimal because VuFind is designed to be very flexible +
-but at the very least every record needs to have an identifier and every record needs to be able to be +
-displayed through some textual representation and so these bare minimum methods are +
-there in abstract base 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 things like titles and authors and subjects and so forth +
-so this allows us to create sort of a standard implementation of bibliographic +
-record information which is shared by a large number of other record drivers +
-so you know whether we're working with data from solar or from a third-party discovery system +
-we're probably in a subclass of default record which just fills in a standard set of methods using +
-data from appropriate places depending on the data source +
-record drivers have their own plugin manager just like pretty much any extensible component of VuFind +
-so well the default is to use the record drivers from the VuFind record driver +
-namespace 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 overrideable it's also worth noting that +
-the way the plugin manager is used varies from search backend to search backend +
-and search back-ends were talked about in last month's video when we went over the search system +
-but the important thing is that whenever we're retrieving data from a search backend +
-VuFind has code that turns it into record drivers so that the rest of the +
-system can interact with it 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 plugin manager and populate it with data for every record that we've got +
-but for records coming from the local solar index we do things in a slightly more +
-sophisticated way because it's possible that we have +
-sort of heterogeneous data in our solar index we might have some mark 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 solar index we may need to display it in different ways +
-and so this is where solar's record format field comes into play +
-for each record that we fetch from solar 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 solar and the value of record format following that so for +
-example if record format is set to mark we look for a solar mark record driver +
-if we find a match we use that if we don't find a match we default to solar +
-default which is another core record driver that provides +
-all of its data based on what has been indexed into solar some of the other drivers like solar +
-mark which i mentioned augment the data in the solar 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's 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 a 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 +
-solarmark they would be in a folder called templates record driver +
-solar mark not using the the VuFind piece of the uh the name +
-again most of vufine's default templates are actually +
-defined in the default record directory because most of what we display by default is +
-bibliographic record type stuff so we just have these core templates +
-that we reuse across all the drivers but if you need to customize something +
-more specifically to a particular record driver all you have to do is create a +
-folder put an override template in there and that will be displayed only for records +
-matching that particular type and of course VuFind uses +
-record driver class inheritance to load the templates so it tries to find the most specific available match so for +
-example if we're displaying a solar mark record +
-based on the discussion earlier solar mark is a child of solar default +
-solar default is a child of default record default record is a child of abstract +
-base uh there's there's a fairly deep inheritance tree in record drivers because of the way we reuse +
-functionality anyway given given the solar mark record +
-if ufi needs to display it in search results it's going to look and see do we have a solar mark search result template if +
-so use it if not let's check if we have a solar default +
-result template if we if we do use it nope we don't so we fall back another level there is +
-the default record search result template that's what's going to end up getting +
-used so again understanding these relationships between the templates and the classes +
-and the ability to override is useful both to find the things that you want to +
-customize and also to override things at the right level of specificity +
-so enough about record drivers let's dive a little bit deeper into the record +
-data formatter the record data formatter is a view helper that was introduced in VuFind +
-four and its purpose is to display tables of data +
-extracted from record drivers using a configuration driven approach +
-are the reason that this was built is that prior to VuFind four +
-many of the custom templates record driver specific templates that i described earlier +
-were basically really long html tables full of you know labels and values +
-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'+
-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 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 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 uh +
-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 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 format or factory you will find all of the default configurations for 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's a method that builds each of the default configurations which all makes it +
-easy to extend and override and customize the configuration of +
-each area is just a big php array with various settings +
-explaining to the helper how it needs to display all the fields but because this is a pretty large and +
-unwieldy data structure we've built a record data formatter spec builder class +
-which provides some convenience methods for building this array and reorganizing +
-it the most common ways of +
-describing fields in this configuration are either just specifying there's a +
-method on the record driver call that and display all the values you get back from it +
-or in a slightly more sophisticated way rendering a custom template so call +
-record driver method and then render this template using that data as input +
-so the direct method approach is useful if you just want to display a value and you +
-don't need to do anything special with it the template approach is more useful if +
-you need to do special formatting or make it have outgoing links or things like that +
-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 formatter 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's a great deal of flexibility here but it can get a little complicated +
-so as i say given the amount of time we have for this video i can't do too deep +
-of a dive into all of this but i encourage you take a look at the record data formatter factory code +
-this will show you how the record data formatter is set up by default and also take a look at the record data +
-formatter wiki page which explains all of the settings that can go into the +
-php array to configure the record data formatter and also lists all of the spec builder methods that you can use to +
-build the configuration so for most things you can get away with +
-fairly simple calls to just add a method based field or add a custom template +
-but if you need to get deeper into it there are some really sophisticated things you can do like building custom +
-functions that return a map of labels to values +
-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 it 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 formatter 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 597 a +
-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 mark 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 mark record with an author a title a 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 view find home directory +
-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 mark 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 mark record and be done with it but in general i think it's a little +
-more useful to pull the data into solar 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 solar from various formats then you only need to write one set of code to pull the data +
-from the solar 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 +
-mark local properties file i'm going to go down to the bottom and i'm just going to create a custom field +
-called donor str mv which is a multi-valued string field +
-taking advantage of the dynamic field suffixes defined in +
-VuFind solar schema i'm going to say donor string mv equals +
-597 a i'm going to save that file then i'm going to go to the command line and i'm +
-going to run import mark.sh on my example mark record +
-to index it this will take just a moment +
-and there we go our record with 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's my 597a but of course +
-we're not displaying our donor note up here in the core metadata like we want to because we haven't done that customization yet +
-so let me show you how to add that and this is going to require us to +
-customize both record driver and record data formatter +
-so the first step is we need to create a custom record driver +
-that has a method in it that can retrieve the donor information +
-and i'm going to use the extend class code generator which we +
-demonstrated in an earlier video to build myself a new +
-record driver so i'm going to say php public index.php generate +
-extend class and i'm going to extend the VuFind record driver +
-solar mark driver into the tutorial module +
-so in this instance we know that we're only going to have this donor note in our mark 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 we might have to extend multiple classes and we +
-could perhaps create a custom trait to share this functionality between them +
-but for the purposes of this demo we're doing things in the simplest possible way i'm just extending the one class +
-so my generator has now set up for me in my tutorial module +
-this solar mark record driver which has nothing in it so i just need to add a public function +
-here to provide the donor information +
-so that we can get access to it from the record data formatter so i'm just going to paste some code in +
-here we create public function get donors and this just returns +
-this field donor strmv and if there's nothing there it defaults to an +
-empty array so in all of the record drivers extending solar default there's a +
-property called this fields and it's just an array indexed by solar +
-field name so this is how you can gain direct access to anything you put in the solar index +
-so that is all i need to do there now because i've created a +
-new class which has edited my module configuration i do also need to remember +
-to clear my configuration cache so that VuFind knows +
-to load the updated configuration so i'm just going to quickly before i forget +
-delete the contents of the local cache config directory +
-so that will not confuse me later now the next step is i want to create a +
-custom record data formatter factory so i can adjust the configuration of the +
-record data formatter to display this new donor field +
-so first thing i'm going to do is just create an empty directory +
-in my tutorial module for the factory since we haven'+
-created anything uh custom related to view helpers yet this directory doesn't exist +
-and i'm just going to create it at the command line here so that i don't have to create a whole bunch of nested folders in vs code which is less +
-efficient so as i mentioned the core default +
-record data formatter settings are found in if you find view helper root record data formatter +
-factory so i'm just creating an equivalent directory structure in my tutorial module where i can extend that +
-now we don't currently have a code generator that is particularly well suited to +
-overriding this kind of factory so i'm just going to create this whole custom factory by hand +
-so i'm creating record data formatter factory dot php +
-in that directory that i just built and i'm going to paste some code straight in here +
-and then i'll walk you through it so here is our custom factory +
-for namespace of course we have to match our directory structure so it's tutorial view helper root +
-uh we're going to make use of that spec builder helper class for setting up the configuration so i just have a use +
-statement to make that code accessible here +
-and then my class definition my local record data formatter factory extends +
-the core record data formatter factory and as i explained earlier +
-the core record data formatter factory has a method for each of the uh default +
-configurations that it manages so there's one called get default core +
-specs which is how we set up the core metadata and what i want to do +
-is simply add a line to that so what i do is i create a new spec +
-builder which is that helper class for manipulating these configurations and i initialize it using the output of +
-the parent version of this method so i load the existing default core specs into the spec builder +
-so 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 and set line is the simplest option this +
-just says i want to label this donor note and i want it to display any or all values coming from the record +
-drivers get donors method which we just defined earlier and then my method returns a call to +
-spec get array which turns my spec builder object back into a php configuration array +
-and that's it 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's just one last thing we need to do we've created this custom factory but +
-we need to actually register it in our theme so because this factory is building a +
-view helper and view helpers are specific to themes i need to go into my custom theme +
-and find the theme.config.php file there +
-and i just need to create a helpers section inside that file so again i'm just going +
-to paste some code in here add a comma the end of our css there so that it parses correctly +
-and then paste in this helpers so the helpers section of your theme configuration is where all the view +
-helpers are defined inside the helper section there's a factories section this is how we tell +
-VuFind which factory to use to build which helper so here we just want to say +
-for the existing core record data formatter class we want to use our local custom factory which has added a little +
-bit of extra special logic so all i have to do is save that and we're done we have a configuration +
-telling VuFind to build the record data formatter using a custom factory +
-that custom factory just adds a line to one of the default configurations for record display +
-which makes use of a custom record driver that we just built so we've essentially edited three files +
-and we're now ready to test this out so if i refresh this page +
-and there it is donor note number 41 donated by damian katz +
-and that's it so thank you for +
-sitting through all of this background and this demo as i say there's a lot more that you can +
-learn i certainly encourage you if you're interested to examine the code +
-read the learning VuFind book and reach out with questions if there's anything else the community can help you +
-with thanks for your time and bye for now+
  
 +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's code is designed to either load particular logic based on the presence of capabilities or to gracefully degrade if we want to do something and we can't. All of this is designed again to make it possible to write fairly generic, fairly reusable code and have it interact successfully with all kinds of different data because VuFind is designed to let you index practically anything and also to interact with a number of external systems that format data in different ways. Of course, with all of the possibilities that are out there, it would be easy to end up with a lot of redundant and complicated and contradictory code, but VuFind uses features of the PHP language, particularly treats and inheritance to make code as reusable as possible and to share features across multiple drivers. So in order to understand record drivers, having a good understanding of PHP object-oriented logic is helpful. So let's go into a little more detail on the PHP side of things. So every record driver is a PHP class and all of these classes can be found in the VuFind record driver namespace. There are a few record driver classes that are particularly important. One is called abstract base. This is an abstract base class as the name suggests and all of the record drivers extend to this class either directly or indirectly. And this is where the absolute bare minimum functionality for record drivers lives. All of the things that every record driver has to be able to do are implemented here. And this is fairly minimal because VuFind is designed to be very flexible. But at the very least, every record needs to have an identifier and every record needs to be able to be displayed through some textual representation. And so these bare minimum methods are there in abstract base.
 +
 +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, things like titles and authors and subjects and so forth. So this allows us to create sort of a standard implementation of bibliographic record information which is shared by a large number of other record drivers. So whether we're working with data from Solr or from a third-party discovery system, we're probably in a subclass of default record which just fills in a standard set of methods using data from appropriate places depending on the data source.
 +
 +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's video when we went over the search system. But the important thing is that whenever we're retrieving data from a search backend, VuFind has code that turns it into record drivers so that the rest of the system can interact with it.
 +
 +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's default templates are actually defined in the default record directory because most of what we display by default is bibliographic record type stuff. So we just have these core templates that we reuse across all the drivers, but if you need to customize something more specifically to a particular record driver, all you have to do is create a folder, put an override template in there, and that will be displayed only for records matching that particular type. And of course, VuFind uses record driver class inheritance to load the templates, so it tries to find the most specific available match. So for example, if we're displaying a MARC record based on the discussion earlier, MARC is a child of Solr default, Solr default is a child of default record, default record is a child of abstract base. There's a fairly deep inheritance tree in record because of the way we reuse functionality. Anyway, given given the MARC record, if VuFind needs to display it in search results, it's going to look and see, do we have a MARC search result template? If so, use it. If not, let's check if we have a Solr default result template. If we do use it, no, we don't. So we fall back another level. There is the default record search result template. That's what's going to end up getting used. So again, understanding these relationships between the templates and the classes and the ability to override is useful both to find the things that you want to customize and also to override things at the right level of specificity. So enough about record drivers, let's dive a little bit deeper into the record data formatter. The record data formatter is a view helper that was introduced in VuFind 4 and its purpose is to display tables of data extracted from record drivers using a configuration driven approach. The reason that this was built is that prior to VuFind 4 many of the custom templates record driver specific templates that I described earlier were basically really long HTML tables full of labels and values.
 +
 +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's a method that builds each of the default configurations which all makes it easy to extend and override and customize. The configuration of each area is just a big PHP array with various settings explaining to the helper how it needs to display all the fields. But because this is a pretty large and unwieldy data structure, we've built a record data format or spec builder class which provides some convenience methods for building this array and reorganizing it.
 +
 +The most common ways of describing fields in this configuration are either just specifying there's a method on the record driver call that and display all the the values you get back from it or in a slightly more sophisticated way rendering a custom template. So call record driver method and then render this template using that data as input. So the direct method approach is useful if you just want to display a value and you don't need to do anything special with it. The template approach is more useful if you need to do special formatting or make it have outgoing links or things like that.
 +
 +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's a great deal of flexibility here but it can get a little complicated. So as I say, given the amount of time we have for this video, I can't do too deep of a dive into all of this but I encourage you take a look at the record data format or factory code. This will show you how the record data format is set up by default and also take a look at the record data format or wiki page which explains all of the settings that can go into the PHP array to configure the record data format and also lists all of the spec builder methods that you can use to build the configuration. So for most things, you can get away with fairly simple calls to just add a method-based field or add a custom template but if you need to get deeper into it, there are some really sophisticated things you can do like building custom functions that return a map of labels to values.
 +
 +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's my 597A, but of course we're not displaying our donor note up here in the core metadata like we want to because we haven't done that customization yet. So let me show you how to add that. And this is going to require us to customize both record driver and record data for matter. So the first step is we need to create a custom record driver that has a method in it that can retrieve the donor information. And I'm going to use the extend class code generator, which we demonstrated in an earlier video, to build myself a new record driver. So I'm going to say PHP, public index.php, generate, extend class. And I'm going to extend the VuFind record driver Solr MARC driver into the tutorial module.
 +
 +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, we might have to extend multiple classes and we could perhaps create a custom trait to share this functionality between them. But for the purposes of this demo, we're doing things in the simplest possible way. I'm just extending the one class. So my generator has now set up for me in my tutorial module, this Solr MARC record driver, which has nothing in it. So I just need to add a public function here to provide the donor information so that we can get access to it from the record data for matter. So I'm just going to paste some code in here. We create public function, get donors, and this just returns this field donor STRMV. And if there's nothing there, it defaults to an empty array. So in all of the record drivers extending Solr default, there's a property called this fields. And it's just an array indexed by Solr field name. So this is how you can gain direct access to anything you put in the Solr index. So that is all I need to do there. Now, because I've created a new class, which has edited my module configuration, I do also need to remember to clear my configuration cache so that VuFind knows to load the updated configuration. So I'm just going to quickly, before I forget, delete the contents of the local cache config directory. So that will not confuse me later. Now, the next step is I want to create a custom record data for matter factory, so I can adjust the configuration of the record data for matter to display this new donor field. So first thing I'm going to do is just create an empty directory in my tutorial module for the factory. Since we haven't created anything custom related to view helpers yet, this directory doesn't exist. And I'm just going to create it at the command line here so that I don't have to create a whole bunch of nested folders in VS code, which is less efficient.
 +
 +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's one called get default core specs, which is how we set up the core metadata.
 +
 +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's method, which we just defined earlier.
 +
 +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's just one last thing we need to do. We've created this custom factory, but we need to actually register it in our theme. So because this factory is building a view helper and view helpers are specific to themes, I need to go into my custom theme and find the theme.config.php file there. And I just need to create a helper's section inside that file. So again, I'm just going to paste some code in here, add a comma, the end of our CSS there so that it parses correctly, and then paste in this helpers. So the helper section of your theme configuration is where all the view helpers are defined. Inside the helper section, there's a factories section. This is how we tell view find which factory to use to build which helper. So here we just want to say, for the existing core record data formatter class, we want to use our local custom factory, which has added a little bit of extra special logic. So all I have to do is save that and we're done. We have a configuration telling view find to build the record data formatter using a custom factory. That custom factory just adds a line to one of the default configurations for record display which makes use of a custom record driver that we just built. So we've essentially edited three files and we're now ready to test this out. So if I refresh this page and there it is. Donor note number 41 donated by Damian Katz. And that's it. So thank you for sitting through all of this background and this demo. As I say, there's a lot more that you can learn. I certainly encourage you if you're interested to examine the code, read the learning view find book and reach out with questions. If there's anything else, the community can help you with. Thanks for your time and bye for now.
 +
 +// This is an edited version of an automated transcript. Apologies for any errors. //
 ---- struct data ---- ---- struct data ----
 +properties.Page Owner : 
 ---- ----
  
videos/customizing_record_views.1651749921.txt.gz · Last modified: 2022/05/05 11:25 by demiankatz