Fire Emblem Heroes Wiki:Tutorials/Cargo

From Fire Emblem Heroes Wiki
Jump to: navigation, search

This article may need cleanup to meet quality standards.
Please help improve this if you can. The Discussion page may contain suggestions.
Reason: "Use a template that isn't deprecated."

This wiki uses the Cargo extension for storing and querying data, acting essentially as a database. This allows for automated methods of creating some pages (eg. Lists), reducing the need for manual maintenance across several pages. A list of all Cargo tables can be found at Special:CargoTables.

Without Cargo, there might be the same information across multiple pages maintained manually (eg. Hero stats are used in multiple places). Previously, these pages needed to all be updated manually any time information changed. If all these pages instead use Cargo to grab the information from the Cargo table, we simply only need to change the information within the Cargo table. Then, all the pages pulling data from the Cargo table would pull the new values and automatically update accordingly.

Understanding Templates[edit source]

Cargo tables are declared and stored into via templates, so understanding Cargo also requires a basic understanding of how templates work. See the tutorial section for templates.

General Overview[edit source]

A simplification of Cargo is as follows:

  • Create/declare the Cargo table
  • Store information into the Cargo table
  • Query information from the Cargo table

The following sections will visit each topic more in-depth.

Declaring the Cargo Table[edit source]

To have a table to store information into, we must first create the table and also decide what kind of information we want stored in the table.

This is done inside the <noinclude></noinclude> tags in the template. For more details on what those tags do, see the MediaWiki article on Partial Transclusion, but in short, if we don't put the table declaration in those tags, the declare statement will be called wherever the template is called. We only want it called once on the Template page itself.

The tag for declaring the Cargo table is cargo_declare. Inside the cargo_declare, you will then specify:

  • Name of what you want to call the new table using _table=
  • Name and type (eg. Integer, String, Date, etc) of the columns you want to have in the table

Example[edit source]

Here is the Cargo declaration from Template:Summon Focus which stores information about summoning focuses that occur in-game (eg. Legendary Banners, Tempest Trial Banners, New Hero Banners, etc.).

{{#cargo_declare:
 _table=SummoningFocuses
 |StartDate=Date
 |EndDate=Date
 |BannerType=String
 |FocusHeroes=List (;) of Page
}}

In this cargo_declare, the above:

  • Names the table SummoningFocuses
  • Creates four parameters/columns to be in the table
    • StartDate - The date a banner starts on.
      • It has type Date so that only Date inputs can be accepted (eg. FEH Wiki won't be accepted as input to store into the table since it is not a date.)
    • EndDate - The date a banner ends on. Type is same as above.
    • BannerType - The type of banner this is (eg. Legendary Banner, New Hero Banner, etc.).
      • This is type String, which is essentially just text. Any text will generally be accepted if a column is type String.
    • FocusHeroes - All the focus heroes in a banner.
      • The type specified here is different in that it is a List. This means it can store multiple values of the type specified after. In this case, List of Pages (There can also be List of String, List of Date, etc.). The (;) represents the character(s) which separate each item in the list which in this case is a semicolon. Sample list input in this case would look like Marth;Lucina;Chrom. If we wanted to use another symbol, like a comma, we could change this to be List (,) of Page.

To create this table, you must first save the template and go to More > Recreate Data or add ?action=recreatedata to the end of the template URL. This option is only available to admins, so if you do not have the permission to create tables, contact an administrator. Every time the cargo_declare is modified, a table must be recreated for those changes to show up in the actual table.

After the table is created, go to Special:CargoTables to find the table. For this example, here is the SummoningFocus table with all the information we specified from the code snippet above.

Storing Information into the Cargo Table[edit source]

After you've created a new table, there won't be any rows of information yet in the table. To store information, we need to add cargo_store tags into the template. These will go outside the <noinclude></noinclude> tags, else information won't get stored and specify what information will get stored in the table.

The cargo_store follows a similar format where you:

  • Specify the table name to store info into
  • List out all the parameters/columns you want to store info into and the information you want to store.

Example[edit source]

Here is the example cargo_store for Template:Summon Focus.

{{#cargo_store:
 _table=SummoningFocuses
 |StartDate={{{start|}}}
 |EndDate={{{end|}}}
 |BannerType={{{bannerType|}}}
 |FocusHeroes={{{hero1|}}};{{{hero2|}}};{{{hero3|}}};{{{hero4|}}};{{{hero5|}}};{{{hero6|}}};{{{hero7|}}};{{{hero8|}}};{{{hero9|}}};{{{hero10|}}};{{{hero11|}}};{{{hero12|}}}
}}

As mentioned, inside the cargo_store we specify:

  • The name of the table we want to store into
    • In this case, SummoningFocuses
  • All the parameters and what values we want to store into them.

This template stores the template parameters into each field. As a reminder, the triple curly bracket text are template parameters passed in. The template parameters from the above code are:

  • {{{start|}}}
  • {{{end|}}}
  • {{{bannerType|}}}
  • {{{hero1|}}}
  • {{{hero2|}}}
  • etc.

These are the parameters we specify when calling the template. The Summon Focus template actually has more than just these as template parameters such as rarity3Percent rarity4Percent, etc., but these are the parameters we want stored into the Cargo table. The following is what a Summon Focus template call would look like, using the Wikicode from Scattered_Fangs_(Focus) as the example.

{{Summon Focus
|name=Scattered Fangs
|bannerType=New Heroes
|description=Summoning focus with new heroes from ''[[:Category:Fire Emblem: The Blazing Blade|The Blazing Blade]]''.
|rarity5FocusPercent=3.00%
|rarity5Percent=3.00%
|rarity4Percent=58.00%
|rarity3Percent=36.00%
|hero1=Karla: Sword Vassal
|hero2=Legault: The Hurricane
|hero3=Nino: Pale Flower
|start=June 8, 2018
|end=June 21, 2018
}}

Cargo only cares about the parameters we told it to put into the table in the cargo_store. The following table represents what would be stored into the table:

Column Name cargo_store Value Passed to Template to be Stored in Cargo Table
StartDate {{{start|}}} June 8, 2018
EndDate {{{end|}}} June 21, 2018
BannerType {{{bannerType|}}} New Heroes
FocusHeroes {{{hero1|}}};{{{hero2|}}};{{{hero3|}}};{{{hero4|}}};{{{hero5|}}};{{{hero6|}}};{{{hero7|}}};{{{hero8|}}};{{{hero9|}}};{{{hero10|}}};{{{hero11|}}};{{{hero12|}}} Karla: Sword Vassal;Legault: The Hurricane;Nino: Pale Flower;;;;;;;;;

Note. Because the others were not specified, they default to no value, hence the String of semicolons at the end with no values in between.

If you look up this banner in the Summon Focus Cargo Table, you can see that this is the information stored as well. You may notice that all tables have a _pageName column. This column is the page where a template call and the Cargo store happens. In this case, since we called the Summon Focus template from Scattered Fangs (Focus), the stored _pageName is also Scattered Fangs (Focus).

Preventing stores[edit source]

In some cases, it is desirable to reuse a template in situations where Cargo tables must be kept intact, such as inside user pages. Some templates, such as {{Passive}}, allow this to be done using the no cargo parameter. (This is used on the Unused content page to display internal skills without affecting skill queries.) To add no cargo support to your template, the whole cargo_store section needs to be surrounded inside a conditional statement as follows:

{{#if:{{{no cargo|}}}|<!--
// do not store anything if "no cargo" is specified
-->|<!--
// otherwise, proceed
-->{{#cargo_store:_table=<!-- -->}}<!--
// other stores go here
-->}}

Then, when a page transcludes the template while also supplying |no cargo=1 for the template arguments, no rows will be stored by the template.

Since only pages in the main namespace are expected to store rows into Cargo tables through templates, cargo_stores should also be protected with a namespace check using {{#ifeq:{{NAMESPACE}}|{{ns:0}}| ... }}. This check is required for all Cargo table templates.

Other times, if a cargo_store creates fields that would violate the constraints specified in the cargo_declare field descriptions, such as storing duplicate values on a unique column, the store silently fails and the corresponding row is not created.

Querying Information from the Cargo Tables[edit source]

The information stored can now be queried anywhere from the Wiki with a the cargo_query tag. There are also several other methods to query the Cargo tables (eg. cargo_compound_query, via Lua using Scribunto), but this section will only cover doing a basic Cargo query. For more information on complex queries, refer to the Cargo documentation on querying data.

A basic cargo_query expects:

  • The table name you want to query from

This is the only required information you need to specify to query the Cargo table, and it pulls every single row from the Cargo table. However, this isn't particularly useful. Other options you can include to narrow your search include:

  • fields - The columns you want to specify.
  • where - Condition you can specify to filter out results.
    • Conditions follow MYSQL syntax.
  • limit - The max number of results you want returned.
    • Defaults to 100 if not specified.
  • format - The format you want results to be returned in.
    • See Cargo documentation for a full list of formats you can return Cargo queries in.
  • order by - The order you want results to get returned in.

Although not documented on the MediaWiki Cargo page, REGEXP can also be used in place of = or LIKE.

Example[edit source]

The following is an example cargo_query which gets all names and focus heroes of banners that have New Heroes banner type and ordered by their StartDate in ascending order in table format.

{{#cargo_query:
tables=SummoningFocuses
|fields=_pageName,FocusHeroes
|where=BannerType="New Heroes"
|format=table
|order by=StartDate ASC
}}

This code generates the following:

Error: No field named "FocusHeroes" found for any of the specified database tables.

Styling Cargo Query Outputs[edit source]

The above example table output is nice, but there are a few styling issues which could use some work. For example, the column names aren't exactly great header names for the table.

There are three main ways the FEH Wiki creates more complex formats to output in order of complexity. A few examples in the Wiki are included. To view the Cargo query code, view the source of those pages.

  • Using CONCAT() in |fields
  • Creating a template to use in the Cargo query via |format=template
  • Through Scribunto Lua modules
    • e.g. Template:Hero List and Module:HeroList
    • Lua runs much faster than Cargo queries, and a lot of complex data processing can be done in Lua while reducing the number of query calls
    • May also use CONCAT()
    • Queries via Lua do not translate to Cargo display formats directly, so Lua code must also generate the visual layout
    • Invoking the module without a wrapper template can roughly halve the post-expand include size
    • Not recommended for small templates frequently used in plain wikitext as #invoke adds visual noise

Allowed MySQL functions[edit source]

These are the currently allowed functions on the wiki ($wgCargoAllowedSQLFunctions):

  • AVG
  • CEIL
  • CONCAT
  • COUNT
  • DATE
  • DATEDIFF
  • DATE_ADD
  • DATE_FORMAT
  • DATE_SUB
  • DAYOFMONTH
  • FLOOR
  • FORMAT
  • GROUP_CONCAT
  • IF
  • IFNULL
  • IN
  • LCASE
  • LN
  • LOG
  • LOWER
  • MAX
  • MIN
  • MONTH
  • NEAR
  • NOW
  • POWER
  • ROUND
  • SUBSTRING
  • SUM
  • UCASE
  • UPPER
  • YEAR

Common fields on the wiki[edit source]

  • WikiName: This field is intended to uniquely identify a row where a page name is insufficient (because, for example, a page may store multiple distinct objects into the same table where all rows need to be distinguished in joins). These fields are often parsed through Template:MF for filename use for example. WikiName fields should not contain any symbols or Unicode characters to avoid technological issues. WikiName fields are for internal use only, and terminology guidelines should still be followed when actually displaying names. All WikiName fields should add the mandatory and unique constraints.
  • TagID: This field represents the internal string identifier of a row in the game assets. The main purpose of including them in the Cargo database is to allow external scripts to map game entities to wiki page names efficiently. They should not be used in queries for wiki content, but can be freely used in code that generates wikitext from game files, e,g, Module:ScenarioArchiveToWiki. All TagID fields should add the unique constraint, but not mandatory since rows may be created after new information is released but before game files are available through updates.
  • Properties: This field represents an unordered set of properties that apply to a given row. If a property is called abc, the presence of a property can be checked with the following where-clauses:
  • Properties HOLDS 'abc'; Cargo internally translates this to TABLE__Properties._value='abc' with a suitable join, and at most one HOLDS statement can be used on each table.
  • Properties__full LIKE '%abc%'; because of this, properties must not be substrings of other properties, to prevent false positives.
The opposite can be checked with the following where-clauses:
  • Properties__full IS NULL OR Properties__full NOT LIKE '%abc%'
  • IFNULL(Properties__full,'') NOT LIKE '%abc%'
The HOLDS NOT command is not a negation of the HOLDS command; it returns true if the row contains any property that is not equal to abc. The HOLDS commands cannot be used as predicates inside the IF() function as they are purely Cargo extensions.