Whenever we want to expose data to Views, we need to define this data in a way Views can understand it. That is actually what EntityViewsData::getViewsData() does for content entities. However, since we are dealing with something custom, we can do so by implementing hook_views_data(). A lot can go into it, but we'll start things simple.
Let's implement this hook and simply describe our first table (that of the players) and only one field, namely, the player ID, to start with.
So, the basic implementation can look like this:
/** * Implements hook_views_data(). */ function sports_views_data() { $data = []; // Players table $data['players'] = []; $data['players']['table']['group'] = t('Sports'); $data['players']['table']['base'] = array( 'field' => 'id', 'title' => t('Players'), 'help' => t('Holds player data.'), ); // Player fields $data['players']['id'] = array( 'title' => t('ID'), 'help' => t('The unique player ID.'), 'field' => array( 'id' => 'numeric', ), ); return $data; }
This hook needs to return a multi-dimensional associative array that describes various things, the most important being the table and its fields. The table doesn't have to be an actual database table, but can also mean something similar to an external resource. Of course, Views already knows how to query the database table, which makes things easy for us. Otherwise, we'd also have to create the logic for querying that external resource (by implementing a ViewsQuery plugin).
So, we start by defining the players table, which goes into the Sports group. This label can be found in the Views admin as the prefix to the fields we want to add. Next, we define our first base table called players (mapping to the actual database table with the same name). The base table is the one used for basing a View on when creating it. In other words, whatever you select in the following screen text:
The base table definition contains some information, such as the field that refers to the column that contains the unique identifier for the records. title and help, both mandatory, are used in the UI. Moreover, it can also contain query_id, which references the plugin ID of a ViewsQuery plugin responsible for returning the data from the source in an intelligible way. Since, in our case, we are using the database (hence SQL), omitting this property will make it default to the views_query plugin (the Sql class if you want to check it out).