CoolCMS API

CompanyFormTrait uses trait:short, trait:short

Own company add/edit form: fieldset sections (basics, contact and address, presentation, opening hours, highlights, content blocks, team, switches) plus the `activated` header toggle.

The skeleton (check, domain translator, save/apply/cancel buttons and return) is BasePresenter::createForm(). The seller (invoicerSellerId) is a Picker (SellerPickerTrait); invoicerBillingLineId, invoicerInvoiceTypeId and currencyId are DB-driven selects.

Image channels:

  • logo via Form::addImageUpload(): the bytes go to $meta['logo'] and CompanyManager creates the Asset variants,
  • profile gallery (photos and videos; replaces the single-image photo channel, kept in the Api only for backward compatibility) via the uploader Dropzone component: the ordered list (existing + new) goes to the Api in $meta['orderedAssets']; the first item is the hero photo (photoImageId). The form carries only the hidden dropzoneToken (same as ReferenceFormTrait).

IMPORTANT: highlights, content blocks and team members are not owned collections of Company (their entities hold a scalar companyId, not a ManyToOne association), so they are not saved by the object graph with the company. Each has its own sync (saveHighlights(), saveBlocks(), saveTeamMembers()) through its Admin manager: load existing, build entities from the form, save, delete removed rows. This is the only deviation from the object-graph rule in this form.

Team rows carry an <input type=file> (portrait), so the team uses the client-side multiplier (addTeamFields()), not the server-side/Naja one used by highlights and blocks; see also GalleryFormTrait.

Table of Contents

Constants

SUPPLY_KIND_SETTING_MODULE_INVOICER  : mixed = 7
Module "invoicer" in the settings table (`cms_system_settings.module`); holds the portal `sellerId`.

Properties

$supplyKindFieldsManager  : SupplyKindManager
$supplyKindFieldsSellerManager  : SellerManager
$supplyKindFieldsVatRateManager  : VatRateManager

Methods

addSupplyKindSelect()  : SelectBox
Adds the supply kind select. The options are database names, so the select translator is off and the prompt is translated here. IMPORTANT: the label must stay a translation key (`BaseControl::getLabel()` takes the translator from the form); a translated label would be translated twice.
buildSupplyKindRegionVatMaps()  : array<int, array<int, string>>
Returns the rate map for the helper field "price with VAT": `regionId => supplyKindId => percent` (valid today).
buildSupplyKindVatMapAttributes()  : array<int, array{json: string, map: array}>
Returns the same as {@see buildSupplyKindRegionVatMaps()} plus JSON for the `data-price-vat-map` attribute of the region matrix (keys as strings, because JS reads `map[select.value]`).
createComponentEditForm()  : Form
getSupplyKindOptions()  : array<int, string>
Returns active supply kinds as `id => name` in the admin language.
resolveSupplyKindDefaultId()  : int|null
supplyKindIdValue()  : int|null
Converts the supply kind select value to an id, or null for the empty prompt.
addBasicFields()  : void
Basics section: name, seller (picker), invoicing defaults, currency, default hourly rate and VAT rate.
addBehaviorFields()  : void
Switches section: `bookingEnabled`/`ratingEnabled`. `activated` is added here too (a PHP form field) but the template renders it as the header toggle (`admin-status-toggle`), not in this fieldset (the single global activation flag).
addBlockFields()  : void
Content blocks section: a server-side Multiplier, same mechanics as highlights. A row is hidden `id`, `identifier` (anchor for the template), `public` and per language `title_<langId>`/`content_<langId>`. Saved by sync, see {@see saveBlocks()}.
addContactFields()  : void
Contact and address section.
addGalleryFields()  : void
The profile gallery is a Dropzone uploader (`uploader` component). The form carries only the hidden `dropzoneToken` (identifies the temp folder); the component holds the selected files (AJAX upload to temp) and the ordered list (existing + new) arrives in the POST as `uploaderItems[]`. On re-render (validation error) the token is read from the POST.
addHighlightFields()  : void
Highlights section: a server-side Multiplier (no file inputs, Naja add/remove works).
addOpeningHoursFields()  : void
Opening hours section: day 1..7 (Mon..Sun) x interval 0..1 (`oh_{dow}_{i}_from/_to`) plus slot length and reservation lead time. Normalized on save by {@see buildOpeningHours()}.
addTeamFields()  : void
Team section: a client-side Multiplier (`client-multiplier.js`, opt-in `[data-multiplier]` in the template), unlike highlights/blocks.
addTranslationFields()  : void
Presentation section: language tabs (title/slogan/annotation/description) plus the logo (not per language). `CompanyText` has no own `name` (it is on `Company`), only the `active` translation. The hero photo is the first item of the profile gallery, see `addGalleryFields()`.
buildCompanyEntity()  : Company
Builds the company entity. On edit the existing `$this->editedCompany` is mutated (not a new instance), so fields the form does not edit (`logoImageId`/`photoImageId`, `ratingThreadId`, `deleted`, insert/update datetime) stay unchanged. The logo/photo FK is set later by the Api `processCompanyImage()` after the main save (`updateColumn`).
buildOpeningHours()  : array<int, array<int, array{0: string, 1: string}>>|null
Builds `[dow => [[from,to],…]]` from the filled pairs only and normalizes it via {@see OpeningHours}. An empty result returns null (no opening hours).
collectImageMeta()  : array<string, mixed>
Builds `$meta` for the save: a new logo (base64) and/or the delete flag. The Api creates the `Asset` (variants) and sets the FK. The hero photo/gallery goes separately via {@see collectOrderedAssets()}.
collectOrderedAssets()  : array<int, array{type: string, imageId?: int, name?: string, path?: string, order: int}>
Builds `meta['orderedAssets']` for the Api `afterSave` from the ordered dropzone list (`uploaderItems[]` from the POST): `existing` = id of an existing item, `dropzone` = a newly uploaded file in the temp folder (its `path` is looked up by name). The order is the sequence; the first item is the hero photo. Same as {@see ReferenceFormTrait::collectOrderedAssets()}.
collectSingleImageMeta()  : void
collectTeamPhotoMeta()  : array<string, mixed>
Builds the portrait `$meta` of one team row for `save()`, same mechanics as {@see ReferenceFormTrait::collectLogoMeta()} but over the values of one multiplier row (not the whole `$values`).
currentLangId()  : int|null
Returns the current language id (for labels), or null when unknown.
getFormLanguages()  : array<int, Language>
Returns the languages for the multilingual form fields (admin `LanguageManager`).
loadBlockDefaults()  : array<int, array<string, mixed>>
Returns the company content blocks as Multiplier rows (edit prefill), sorted by the stored `order`.
loadHighlightDefaults()  : array<int, array<string, mixed>>
Returns the company highlights as Multiplier rows (edit prefill), sorted by the stored `order`.
loadTeamDefaults()  : array<int, array<string, mixed>>
Returns the team members as Multiplier rows (edit prefill), sorted by the stored `order`.
prepareBillingLineOptions()  : array<int, NotTranslate>
prepareCurrencyOptions()  : array<int, NotTranslate>
The name is already translated DB data, not a key, hence `NotTranslate`.
prepareInvoiceTypeOptions()  : array<int, NotTranslate>
The name is already translated DB data, not a key, hence `NotTranslate`.
resolveSupplyKindSellerCountryCode()  : string|null
Returns the portal seller country (`7/invoice.default.sellerId`) as a fallback for a region without a country; null when the seller is not found.
saveBlocks()  : bool
Syncs content blocks, same procedure as {@see saveHighlights()}: find the existing blocks of the company, build entities from the form (a new instance with `setId` for existing rows), save and delete removed rows.
saveEditForm()  : bool
Saves the form data. The redirect (to the previous page / "this") is handled by {@see \App\Core\Base\Admin\BasePresenter::createForm()}.
saveHighlights()  : bool
Syncs highlights: the only deviation from the object-graph rule in this form (see the trait docblock). Finds the existing highlights of the company, builds entities from the form (a new instance with `setId` for existing rows), saves them and deletes removed rows (ids among the existing ones but not in the form).
saveTeamMembers()  : bool
Syncs team members, same principle as {@see saveHighlights()} and {@see saveBlocks()} (`TeamMember` is a separate entity with a scalar `companyId`, not an owned collection).
setEditFormDefaults()  : void
str()  : string
Safely converts a mixed form value (NEON/ArrayHash) to a string.
tr()  : NotTranslate
Translates a key in the form domain into a ready string (for fields with `setTranslator(null)`).
translatedName()  : string
Returns the entity name (with `translations`) in the current language, falling back to the first non-empty one.

Constants

SUPPLY_KIND_SETTING_MODULE_INVOICER

Module "invoicer" in the settings table (`cms_system_settings.module`); holds the portal `sellerId`.

private mixed SUPPLY_KIND_SETTING_MODULE_INVOICER = 7

Properties

Methods

addSupplyKindSelect()

Adds the supply kind select. The options are database names, so the select translator is off and the prompt is translated here. IMPORTANT: the label must stay a translation key (`BaseControl::getLabel()` takes the translator from the form); a translated label would be translated twice.

protected addSupplyKindSelect(Form $form, string $name, string $labelKey, string|null $promptKey[, string|null $descriptionKey = null ][, int|null $currentId = null ]) : SelectBox
Parameters
$form : Form
$name : string
$labelKey : string
$promptKey : string|null

null = no prompt (the field is required, the first or current kind is preselected)

$descriptionKey : string|null = null
$currentId : int|null = null
Return values
SelectBox

buildSupplyKindRegionVatMaps()

Returns the rate map for the helper field "price with VAT": `regionId => supplyKindId => percent` (valid today).

protected buildSupplyKindRegionVatMaps(iterable<string|int, PaymentRegion> $regions) : array<int, array<int, string>>
Parameters
$regions : iterable<string|int, PaymentRegion>
Return values
array<int, array<int, string>>

buildSupplyKindVatMapAttributes()

Returns the same as {@see buildSupplyKindRegionVatMaps()} plus JSON for the `data-price-vat-map` attribute of the region matrix (keys as strings, because JS reads `map[select.value]`).

protected buildSupplyKindVatMapAttributes(iterable<string|int, PaymentRegion> $regions) : array<int, array{json: string, map: array}>

For the template: regionId => {json, map}.

Parameters
$regions : iterable<string|int, PaymentRegion>
Return values
array<int, array{json: string, map: array}>

getSupplyKindOptions()

Returns active supply kinds as `id => name` in the admin language.

protected getSupplyKindOptions([int|null $keepId = null ]) : array<int, string>
Parameters
$keepId : int|null = null
Return values
array<int, string>

resolveSupplyKindDefaultId()

protected resolveSupplyKindDefaultId(SupplyKindManager $manager, array<int, mixed> $options[, string|null $preferredKey = null ]) : int|null
Parameters
$manager : SupplyKindManager
$options : array<int, mixed>

select options (SupplyKindManager::findSelectOptions())

$preferredKey : string|null = null
Return values
int|null

supplyKindIdValue()

Converts the supply kind select value to an id, or null for the empty prompt.

protected supplyKindIdValue(mixed $value) : int|null
Parameters
$value : mixed
Return values
int|null

addBasicFields()

Basics section: name, seller (picker), invoicing defaults, currency, default hourly rate and VAT rate.

private addBasicFields(Form $form) : void
Parameters
$form : Form

addBehaviorFields()

Switches section: `bookingEnabled`/`ratingEnabled`. `activated` is added here too (a PHP form field) but the template renders it as the header toggle (`admin-status-toggle`), not in this fieldset (the single global activation flag).

private addBehaviorFields(Form $form) : void
Parameters
$form : Form

addBlockFields()

Content blocks section: a server-side Multiplier, same mechanics as highlights. A row is hidden `id`, `identifier` (anchor for the template), `public` and per language `title_<langId>`/`content_<langId>`. Saved by sync, see {@see saveBlocks()}.

private addBlockFields(Form $form) : void

content is a plain textarea on purpose, not addEditor(): a block holds ready-made HTML and a rich-text editor would rewrite or trim it on save.

IMPORTANT: there is no order field; as for highlights, row order is the DOM position and saveBlocks() derives it.

Parameters
$form : Form

addContactFields()

Contact and address section.

private addContactFields(Form $form) : void
Parameters
$form : Form

addGalleryFields()

The profile gallery is a Dropzone uploader (`uploader` component). The form carries only the hidden `dropzoneToken` (identifies the temp folder); the component holds the selected files (AJAX upload to temp) and the ordered list (existing + new) arrives in the POST as `uploaderItems[]`. On re-render (validation error) the token is read from the POST.

private addGalleryFields(Form $form) : void
Parameters
$form : Form

addHighlightFields()

Highlights section: a server-side Multiplier (no file inputs, Naja add/remove works).

private addHighlightFields(Form $form) : void

A row is hidden id (existing highlight), icon, public and per language label_<langId>/value_<langId>. Saved by sync, not the object graph, see saveHighlights() and the trait docblock.

IMPORTANT: there is no order field. Row order is the DOM position (drag handle, [data-sortable] in the template) and the server derives it from the order of the posted array in saveHighlights().

Parameters
$form : Form

addOpeningHoursFields()

Opening hours section: day 1..7 (Mon..Sun) x interval 0..1 (`oh_{dow}_{i}_from/_to`) plus slot length and reservation lead time. Normalized on save by {@see buildOpeningHours()}.

private addOpeningHoursFields(Form $form) : void
Parameters
$form : Form

addTeamFields()

Team section: a client-side Multiplier (`client-multiplier.js`, opt-in `[data-multiplier]` in the template), unlike highlights/blocks.

private addTeamFields(Form $form) : void

IMPORTANT: a row carries an <input type=file> (portrait), and any Naja snippet redraw would wipe the file the browser selected (a file input cannot be filled programmatically). So the server-side Multiplier has no addCreateButton()/addRemoveButton() and serves only as a container; adding/removing rows in the DOM is done by client JS (see edit.latte and GalleryFormTrait::addImageMultiplier()).

A row is a plain Container, so addText()/addInteger() do not add the Bootstrap form-control class (only BootstrapForm decorates itself); it is set by hand.

photoUrl is an extra hidden field (not saved, ignored on the save path) that carries the preview URL of the existing portrait so the template renders it without an Asset query in the loop (same trick as imageUrl in GalleryFormTrait::addImageRowControls()).

description_<langId> is addSimpleEditor() (trimmed TinyMCE), not addTextArea() as in blocks: it is a short editorial text written in the admin, not ready-made HTML. addEditor()/addImageUpload() work on a plain Container through the extension methods (Form::registerExtensionMethods()).

IMPORTANT: there is no order field; as for highlights/blocks, row order is the DOM position (drag handle, [data-sortable]) and the server derives it in saveTeamMembers(). SortableJS binds to the container on page load, so a freshly cloned row fits in automatically. Saved by sync, see saveTeamMembers().

Parameters
$form : Form

addTranslationFields()

Presentation section: language tabs (title/slogan/annotation/description) plus the logo (not per language). `CompanyText` has no own `name` (it is on `Company`), only the `active` translation. The hero photo is the first item of the profile gallery, see `addGalleryFields()`.

private addTranslationFields(Form $form) : void
Parameters
$form : Form

buildCompanyEntity()

Builds the company entity. On edit the existing `$this->editedCompany` is mutated (not a new instance), so fields the form does not edit (`logoImageId`/`photoImageId`, `ratingThreadId`, `deleted`, insert/update datetime) stay unchanged. The logo/photo FK is set later by the Api `processCompanyImage()` after the main save (`updateColumn`).

private buildCompanyEntity(ArrayHash<string|int, mixed> $values) : Company
Parameters
$values : ArrayHash<string|int, mixed>
Return values
Company

buildOpeningHours()

Builds `[dow => [[from,to],…]]` from the filled pairs only and normalizes it via {@see OpeningHours}. An empty result returns null (no opening hours).

private buildOpeningHours(ArrayHash<string|int, mixed> $values) : array<int, array<int, array{0: string, 1: string}>>|null
Parameters
$values : ArrayHash<string|int, mixed>
Return values
array<int, array<int, array{0: string, 1: string}>>|null

collectImageMeta()

Builds `$meta` for the save: a new logo (base64) and/or the delete flag. The Api creates the `Asset` (variants) and sets the FK. The hero photo/gallery goes separately via {@see collectOrderedAssets()}.

private collectImageMeta(ArrayHash<string|int, mixed> $values) : array<string, mixed>
Parameters
$values : ArrayHash<string|int, mixed>
Return values
array<string, mixed>

collectOrderedAssets()

Builds `meta['orderedAssets']` for the Api `afterSave` from the ordered dropzone list (`uploaderItems[]` from the POST): `existing` = id of an existing item, `dropzone` = a newly uploaded file in the temp folder (its `path` is looked up by name). The order is the sequence; the first item is the hero photo. Same as {@see ReferenceFormTrait::collectOrderedAssets()}.

private collectOrderedAssets(ArrayHash<string|int, mixed> $values) : array<int, array{type: string, imageId?: int, name?: string, path?: string, order: int}>
Parameters
$values : ArrayHash<string|int, mixed>
Return values
array<int, array{type: string, imageId?: int, name?: string, path?: string, order: int}>

collectSingleImageMeta()

private collectSingleImageMeta(ArrayHash<string|int, mixed> $values, string $field, array<string, mixed> &$meta) : void
Parameters
$values : ArrayHash<string|int, mixed>
$field : string
$meta : array<string, mixed>

collectTeamPhotoMeta()

Builds the portrait `$meta` of one team row for `save()`, same mechanics as {@see ReferenceFormTrait::collectLogoMeta()} but over the values of one multiplier row (not the whole `$values`).

private collectTeamPhotoMeta(ArrayHash<string|int, mixed>|array<string, mixed> $row) : array<string, mixed>
Parameters
$row : ArrayHash<string|int, mixed>|array<string, mixed>
Return values
array<string, mixed>

currentLangId()

Returns the current language id (for labels), or null when unknown.

private currentLangId() : int|null
Return values
int|null

getFormLanguages()

Returns the languages for the multilingual form fields (admin `LanguageManager`).

private getFormLanguages() : array<int, Language>
Return values
array<int, Language>

loadBlockDefaults()

Returns the company content blocks as Multiplier rows (edit prefill), sorted by the stored `order`.

private loadBlockDefaults(int $companyId) : array<int, array<string, mixed>>
Parameters
$companyId : int
Return values
array<int, array<string, mixed>>

loadHighlightDefaults()

Returns the company highlights as Multiplier rows (edit prefill), sorted by the stored `order`.

private loadHighlightDefaults(int $companyId) : array<int, array<string, mixed>>
Parameters
$companyId : int
Return values
array<int, array<string, mixed>>

loadTeamDefaults()

Returns the team members as Multiplier rows (edit prefill), sorted by the stored `order`.

private loadTeamDefaults(int $companyId) : array<int, array<string, mixed>>

photoUrl (portrait preview) is resolved by the presenter's CompanyPresenter::resolveAssetUrl(), which the company logo uses too.

Parameters
$companyId : int
Return values
array<int, array<string, mixed>>

prepareBillingLineOptions()

private prepareBillingLineOptions() : array<int, NotTranslate>
Return values
array<int, NotTranslate>

prepareCurrencyOptions()

The name is already translated DB data, not a key, hence `NotTranslate`.

private prepareCurrencyOptions() : array<int, NotTranslate>
Return values
array<int, NotTranslate>

prepareInvoiceTypeOptions()

The name is already translated DB data, not a key, hence `NotTranslate`.

private prepareInvoiceTypeOptions() : array<int, NotTranslate>
Return values
array<int, NotTranslate>

resolveSupplyKindSellerCountryCode()

Returns the portal seller country (`7/invoice.default.sellerId`) as a fallback for a region without a country; null when the seller is not found.

private resolveSupplyKindSellerCountryCode() : string|null
Return values
string|null

saveBlocks()

Syncs content blocks, same procedure as {@see saveHighlights()}: find the existing blocks of the company, build entities from the form (a new instance with `setId` for existing rows), save and delete removed rows.

private saveBlocks(ArrayHash<string|int, mixed> $values, int $companyId) : bool
Parameters
$values : ArrayHash<string|int, mixed>
$companyId : int
Return values
bool

saveEditForm()

Saves the form data. The redirect (to the previous page / "this") is handled by {@see \App\Core\Base\Admin\BasePresenter::createForm()}.

private saveEditForm(ArrayHash<string|int, mixed> $values) : bool
Parameters
$values : ArrayHash<string|int, mixed>
Return values
bool

saveHighlights()

Syncs highlights: the only deviation from the object-graph rule in this form (see the trait docblock). Finds the existing highlights of the company, builds entities from the form (a new instance with `setId` for existing rows), saves them and deletes removed rows (ids among the existing ones but not in the form).

private saveHighlights(ArrayHash<string|int, mixed> $values, int $companyId) : bool
Parameters
$values : ArrayHash<string|int, mixed>
$companyId : int
Return values
bool

saveTeamMembers()

Syncs team members, same principle as {@see saveHighlights()} and {@see saveBlocks()} (`TeamMember` is a separate entity with a scalar `companyId`, not an owned collection).

private saveTeamMembers(ArrayHash<string|int, mixed> $values, int $companyId) : bool

For every row it also builds the portrait $meta (photo/photoDelete) like ReferenceFormTrait::collectLogoMeta() and passes it to save($member, $meta); the Api TeamMemberManager::processPhoto() already handles $meta['photo'].

Parameters
$values : ArrayHash<string|int, mixed>
$companyId : int
Return values
bool

str()

Safely converts a mixed form value (NEON/ArrayHash) to a string.

private str(mixed $value) : string
Parameters
$value : mixed
Return values
string

tr()

Translates a key in the form domain into a ready string (for fields with `setTranslator(null)`).

private tr(string $key) : NotTranslate

IMPORTANT: the result goes to setPrompt()/setRequired() on a field with setTranslator(null). Prompt and items respect the control override, but Nette getLabel() and Validator::formatMessage() always take the translator from the form; without NotTranslate the finished text would be translated again as a key and Tracy would report a missing translation.

Parameters
$key : string
Return values
NotTranslate

translatedName()

Returns the entity name (with `translations`) in the current language, falling back to the first non-empty one.

private translatedName(object $entity) : string
Parameters
$entity : object
Return values
string
On this page

Search results