From 53260d64bccf113062fa77dc128de9276db5143f Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 8 Feb 2024 12:56:15 +0000 Subject: [PATCH] deploy: 159faa4f9d244cc2b52a2e3bdda200ffadb2de6c --- 404.html | 4 ++-- assets/js/1f4f2990.6785e7f1.js | 1 - assets/js/1f4f2990.8bcc2ebe.js | 1 + assets/js/6459b84b.257a7b0e.js | 1 - assets/js/6459b84b.a79374b0.js | 1 + ...ntime~main.35c54bbc.js => runtime~main.54e3bf55.js} | 2 +- .../apiato-containers/debugger/index.html | 4 ++-- .../apiato-containers/documentation/index.html | 4 ++-- .../apiato-containers/localization/index.html | 4 ++-- .../apiato-containers/overview/index.html | 4 ++-- .../apiato-containers/payments/index.html | 4 ++-- .../apiato-containers/settings/index.html | 4 ++-- .../apiato-containers/social-authentication/index.html | 4 ++-- .../community-containers/overview/index.html | 4 ++-- docs/10.x/contribution-guide/index.html | 4 ++-- docs/10.x/core-features/api-versioning/index.html | 4 ++-- docs/10.x/core-features/authentication/index.html | 4 ++-- docs/10.x/core-features/authorization/index.html | 4 ++-- docs/10.x/core-features/code-generator/index.html | 4 ++-- docs/10.x/core-features/data-caching/index.html | 4 ++-- docs/10.x/core-features/default-endpoints/index.html | 4 ++-- docs/10.x/core-features/etag/index.html | 4 ++-- docs/10.x/core-features/hash-id/index.html | 4 ++-- docs/10.x/core-features/pagination/index.html | 4 ++-- docs/10.x/core-features/profiler/index.html | 4 ++-- docs/10.x/core-features/query-parameters/index.html | 4 ++-- docs/10.x/core-features/rate-limiting/index.html | 4 ++-- docs/10.x/core-features/useful-commands/index.html | 4 ++-- docs/10.x/core-features/user-registration/index.html | 4 ++-- docs/10.x/core-features/validation/index.html | 4 ++-- docs/10.x/faq/index.html | 4 ++-- .../getting-started/container-installer/index.html | 4 ++-- .../conventions-and-principles/index.html | 4 ++-- docs/10.x/getting-started/installation/index.html | 4 ++-- docs/10.x/getting-started/markdown-features/index.html | 4 ++-- docs/10.x/getting-started/requests/index.html | 4 ++-- docs/10.x/getting-started/responses/index.html | 4 ++-- docs/10.x/getting-started/samples/index.html | 4 ++-- .../software-architectural-patterns/index.html | 4 ++-- docs/10.x/index.html | 4 ++-- docs/10.x/main-components/actions/index.html | 4 ++-- docs/10.x/main-components/controllers/index.html | 4 ++-- docs/10.x/main-components/exceptions/index.html | 4 ++-- docs/10.x/main-components/models/index.html | 4 ++-- docs/10.x/main-components/requests/index.html | 4 ++-- docs/10.x/main-components/routes/index.html | 4 ++-- docs/10.x/main-components/subactions/index.html | 4 ++-- docs/10.x/main-components/tasks/index.html | 4 ++-- docs/10.x/main-components/transformers/index.html | 4 ++-- docs/10.x/main-components/views/index.html | 4 ++-- docs/10.x/miscellaneous/tasks-queuing/index.html | 4 ++-- docs/10.x/miscellaneous/tasks-scheduling/index.html | 4 ++-- docs/10.x/miscellaneous/tests-helpers/index.html | 4 ++-- docs/10.x/optional-components/commands/index.html | 4 ++-- docs/10.x/optional-components/configs/index.html | 4 ++-- docs/10.x/optional-components/criterias/index.html | 4 ++-- docs/10.x/optional-components/events/index.html | 4 ++-- docs/10.x/optional-components/factories/index.html | 4 ++-- docs/10.x/optional-components/helpers/index.html | 4 ++-- docs/10.x/optional-components/jobs/index.html | 4 ++-- docs/10.x/optional-components/languages/index.html | 4 ++-- docs/10.x/optional-components/mails/index.html | 4 ++-- docs/10.x/optional-components/middlewares/index.html | 4 ++-- docs/10.x/optional-components/migrations/index.html | 4 ++-- docs/10.x/optional-components/notifications/index.html | 4 ++-- docs/10.x/optional-components/providers/index.html | 4 ++-- docs/10.x/optional-components/repositories/index.html | 4 ++-- docs/10.x/optional-components/seeders/index.html | 4 ++-- docs/10.x/optional-components/tests/index.html | 4 ++-- docs/10.x/optional-components/values/index.html | 4 ++-- docs/10.x/upgrade-guide/index.html | 4 ++-- docs/11.x/additional-features/documentation/index.html | 4 ++-- docs/11.x/additional-features/localization/index.html | 4 ++-- docs/11.x/additional-features/overview/index.html | 4 ++-- .../social-authentication/index.html | 4 ++-- docs/11.x/contribution-guide/index.html | 4 ++-- docs/11.x/core-features/api-versioning/index.html | 4 ++-- docs/11.x/core-features/authentication/index.html | 4 ++-- docs/11.x/core-features/authorization/index.html | 4 ++-- docs/11.x/core-features/code-generator/index.html | 4 ++-- docs/11.x/core-features/data-caching/index.html | 4 ++-- docs/11.x/core-features/default-endpoints/index.html | 4 ++-- docs/11.x/core-features/etag/index.html | 4 ++-- docs/11.x/core-features/hash-id/index.html | 4 ++-- docs/11.x/core-features/pagination/index.html | 4 ++-- docs/11.x/core-features/profiler/index.html | 4 ++-- docs/11.x/core-features/query-parameters/index.html | 4 ++-- docs/11.x/core-features/rate-limiting/index.html | 4 ++-- docs/11.x/core-features/useful-commands/index.html | 4 ++-- docs/11.x/core-features/user-registration/index.html | 4 ++-- docs/11.x/core-features/validation/index.html | 4 ++-- docs/11.x/faq/index.html | 4 ++-- .../getting-started/container-installer/index.html | 4 ++-- .../conventions-and-principles/index.html | 4 ++-- docs/11.x/getting-started/installation/index.html | 4 ++-- docs/11.x/getting-started/markdown-features/index.html | 4 ++-- docs/11.x/getting-started/requests/index.html | 4 ++-- docs/11.x/getting-started/responses/index.html | 4 ++-- docs/11.x/getting-started/samples/index.html | 4 ++-- .../software-architectural-patterns/index.html | 4 ++-- docs/11.x/index.html | 4 ++-- docs/11.x/main-components/actions/index.html | 4 ++-- docs/11.x/main-components/controllers/index.html | 4 ++-- docs/11.x/main-components/exceptions/index.html | 4 ++-- docs/11.x/main-components/models/index.html | 4 ++-- docs/11.x/main-components/requests/index.html | 4 ++-- docs/11.x/main-components/routes/index.html | 4 ++-- docs/11.x/main-components/subactions/index.html | 4 ++-- docs/11.x/main-components/tasks/index.html | 4 ++-- docs/11.x/main-components/transformers/index.html | 4 ++-- docs/11.x/main-components/views/index.html | 4 ++-- docs/11.x/miscellaneous/tasks-queuing/index.html | 4 ++-- docs/11.x/miscellaneous/tasks-scheduling/index.html | 4 ++-- docs/11.x/miscellaneous/tests-helpers/index.html | 4 ++-- docs/11.x/optional-components/commands/index.html | 4 ++-- docs/11.x/optional-components/configs/index.html | 4 ++-- docs/11.x/optional-components/criterias/index.html | 4 ++-- docs/11.x/optional-components/events/index.html | 4 ++-- docs/11.x/optional-components/factories/index.html | 4 ++-- docs/11.x/optional-components/helpers/index.html | 4 ++-- docs/11.x/optional-components/jobs/index.html | 4 ++-- docs/11.x/optional-components/languages/index.html | 4 ++-- docs/11.x/optional-components/mails/index.html | 4 ++-- docs/11.x/optional-components/middlewares/index.html | 4 ++-- docs/11.x/optional-components/migrations/index.html | 4 ++-- docs/11.x/optional-components/notifications/index.html | 4 ++-- docs/11.x/optional-components/providers/index.html | 4 ++-- docs/11.x/optional-components/repositories/index.html | 4 ++-- docs/11.x/optional-components/seeders/index.html | 4 ++-- docs/11.x/optional-components/tests/index.html | 4 ++-- docs/11.x/optional-components/values/index.html | 4 ++-- docs/11.x/upgrade-guide/index.html | 4 ++-- docs/9.x/contribution-guide/index.html | 4 ++-- docs/9.x/core-features/admin-dashboard/index.html | 4 ++-- docs/9.x/core-features/api-docs-generator/index.html | 4 ++-- docs/9.x/core-features/api-versioning/index.html | 4 ++-- docs/9.x/core-features/authentication/index.html | 4 ++-- docs/9.x/core-features/authorization/index.html | 4 ++-- docs/9.x/core-features/code-generator/index.html | 4 ++-- docs/9.x/core-features/data-caching/index.html | 4 ++-- docs/9.x/core-features/default-endpoints/index.html | 4 ++-- docs/9.x/core-features/etag/index.html | 4 ++-- docs/9.x/core-features/hash-id/index.html | 4 ++-- docs/9.x/core-features/localization/index.html | 4 ++-- docs/9.x/core-features/pagination/index.html | 4 ++-- docs/9.x/core-features/payments/index.html | 4 ++-- docs/9.x/core-features/profiler/index.html | 4 ++-- docs/9.x/core-features/query-parameters/index.html | 4 ++-- docs/9.x/core-features/rate-limiting/index.html | 4 ++-- docs/9.x/core-features/requests-monitor/index.html | 4 ++-- .../core-features/search-query-parameter/index.html | 4 ++-- .../9.x/core-features/social-authentication/index.html | 4 ++-- docs/9.x/core-features/system-settings/index.html | 4 ++-- docs/9.x/core-features/useful-commands/index.html | 4 ++-- docs/9.x/core-features/user-registration/index.html | 4 ++-- docs/9.x/core-features/validation/index.html | 4 ++-- docs/9.x/faq/index.html | 4 ++-- .../conventions-and-principles/index.html | 4 ++-- docs/9.x/getting-started/installation/index.html | 4 ++-- docs/9.x/getting-started/markdown-features/index.html | 4 ++-- docs/9.x/getting-started/overview/index.html | 4 ++-- docs/9.x/getting-started/requests/index.html | 4 ++-- docs/9.x/getting-started/responses/index.html | 4 ++-- .../software-architectural-patterns/index.html | 4 ++-- docs/9.x/index.html | 4 ++-- docs/9.x/main-components/actions/index.html | 4 ++-- docs/9.x/main-components/controllers/index.html | 4 ++-- docs/9.x/main-components/models/index.html | 4 ++-- docs/9.x/main-components/requests/index.html | 4 ++-- docs/9.x/main-components/routes/index.html | 4 ++-- docs/9.x/main-components/subactions/index.html | 4 ++-- docs/9.x/main-components/tasks/index.html | 4 ++-- docs/9.x/main-components/transformers/index.html | 4 ++-- docs/9.x/main-components/transporters/index.html | 4 ++-- docs/9.x/main-components/views/index.html | 4 ++-- docs/9.x/miscellaneous/container-installer/index.html | 4 ++-- docs/9.x/miscellaneous/magical-call/index.html | 4 ++-- docs/9.x/miscellaneous/postman/index.html | 4 ++-- docs/9.x/miscellaneous/tasks-queuing/index.html | 4 ++-- docs/9.x/miscellaneous/tasks-scheduling/index.html | 4 ++-- docs/9.x/miscellaneous/tests-helpers/index.html | 4 ++-- docs/9.x/optional-components/commands/index.html | 4 ++-- docs/9.x/optional-components/configs/index.html | 4 ++-- docs/9.x/optional-components/criterias/index.html | 4 ++-- docs/9.x/optional-components/events/index.html | 4 ++-- docs/9.x/optional-components/exceptions/index.html | 4 ++-- docs/9.x/optional-components/factories/index.html | 4 ++-- docs/9.x/optional-components/jobs/index.html | 4 ++-- docs/9.x/optional-components/languages/index.html | 4 ++-- docs/9.x/optional-components/mails/index.html | 4 ++-- docs/9.x/optional-components/middlewares/index.html | 4 ++-- docs/9.x/optional-components/migrations/index.html | 4 ++-- docs/9.x/optional-components/notifications/index.html | 4 ++-- docs/9.x/optional-components/providers/index.html | 4 ++-- docs/9.x/optional-components/repositories/index.html | 4 ++-- docs/9.x/optional-components/seeders/index.html | 4 ++-- docs/9.x/optional-components/tests/index.html | 4 ++-- docs/9.x/optional-components/values/index.html | 4 ++-- docs/9.x/upgrade-guide/index.html | 4 ++-- docs/architecture-concepts/components/index.html | 4 ++-- docs/architecture-concepts/container/index.html | 4 ++-- docs/architecture-concepts/index.html | 4 ++-- docs/architecture-concepts/porto/index.html | 4 ++-- .../architecture-concepts/request-lifecycle/index.html | 4 ++-- docs/components/index.html | 4 ++-- docs/components/main-components/actions/index.html | 4 ++-- docs/components/main-components/controllers/index.html | 4 ++-- docs/components/main-components/exceptions/index.html | 4 ++-- docs/components/main-components/index.html | 4 ++-- docs/components/main-components/models/index.html | 4 ++-- docs/components/main-components/requests/index.html | 4 ++-- docs/components/main-components/routes/index.html | 4 ++-- docs/components/main-components/subactions/index.html | 4 ++-- docs/components/main-components/tasks/index.html | 4 ++-- .../components/main-components/transformers/index.html | 4 ++-- docs/components/main-components/views/index.html | 4 ++-- .../components/optional-components/commands/index.html | 4 ++-- docs/components/optional-components/configs/index.html | 4 ++-- docs/components/optional-components/events/index.html | 4 ++-- .../optional-components/factories/index.html | 4 ++-- docs/components/optional-components/helpers/index.html | 4 ++-- docs/components/optional-components/index.html | 4 ++-- docs/components/optional-components/jobs/index.html | 4 ++-- docs/components/optional-components/mail/index.html | 4 ++-- .../optional-components/middlewares/index.html | 4 ++-- .../optional-components/migrations/index.html | 4 ++-- .../optional-components/notifications/index.html | 4 ++-- .../components/optional-components/policies/index.html | 4 ++-- .../repository/criterias/index.html | 4 ++-- .../repository/repositories/index.html | 4 ++-- docs/components/optional-components/seeders/index.html | 4 ++-- .../optional-components/service-providers/index.html | 4 ++-- docs/components/optional-components/tests/index.html | 4 ++-- docs/components/optional-components/values/index.html | 4 ++-- docs/consulting/index.html | 4 ++-- docs/framework-features/api-versioning/index.html | 4 ++-- docs/framework-features/code-generator/index.html | 4 ++-- docs/framework-features/etag/index.html | 4 ++-- docs/framework-features/index.html | 4 ++-- docs/framework-features/profiler/index.html | 4 ++-- docs/framework-features/rate-limiting/index.html | 4 ++-- docs/framework-features/rbac/index.html | 4 ++-- docs/getting-started/best-practices/index.html | 4 ++-- .../customized-laravel-components/index.html | 4 ++-- docs/getting-started/installation/index.html | 10 +++++----- docs/next/architecture-concepts/components/index.html | 4 ++-- docs/next/architecture-concepts/container/index.html | 4 ++-- docs/next/architecture-concepts/index.html | 4 ++-- docs/next/architecture-concepts/porto/index.html | 4 ++-- .../architecture-concepts/request-lifecycle/index.html | 4 ++-- docs/next/components/index.html | 4 ++-- .../next/components/main-components/actions/index.html | 4 ++-- .../components/main-components/controllers/index.html | 4 ++-- .../components/main-components/exceptions/index.html | 4 ++-- docs/next/components/main-components/index.html | 4 ++-- docs/next/components/main-components/models/index.html | 4 ++-- .../components/main-components/requests/index.html | 4 ++-- docs/next/components/main-components/routes/index.html | 4 ++-- .../components/main-components/subactions/index.html | 4 ++-- docs/next/components/main-components/tasks/index.html | 4 ++-- .../components/main-components/transformers/index.html | 4 ++-- docs/next/components/main-components/views/index.html | 4 ++-- .../components/optional-components/commands/index.html | 4 ++-- .../components/optional-components/configs/index.html | 4 ++-- .../components/optional-components/events/index.html | 4 ++-- .../optional-components/factories/index.html | 4 ++-- .../components/optional-components/helpers/index.html | 4 ++-- docs/next/components/optional-components/index.html | 4 ++-- .../components/optional-components/jobs/index.html | 4 ++-- .../components/optional-components/mail/index.html | 4 ++-- .../optional-components/middlewares/index.html | 4 ++-- .../optional-components/migrations/index.html | 4 ++-- .../optional-components/notifications/index.html | 4 ++-- .../components/optional-components/policies/index.html | 4 ++-- .../repository/criterias/index.html | 4 ++-- .../repository/repositories/index.html | 4 ++-- .../components/optional-components/seeders/index.html | 4 ++-- .../optional-components/service-providers/index.html | 4 ++-- .../components/optional-components/tests/index.html | 4 ++-- .../components/optional-components/values/index.html | 4 ++-- docs/next/consulting/index.html | 4 ++-- docs/next/framework-features/api-versioning/index.html | 4 ++-- docs/next/framework-features/code-generator/index.html | 4 ++-- docs/next/framework-features/etag/index.html | 4 ++-- docs/next/framework-features/index.html | 4 ++-- docs/next/framework-features/profiler/index.html | 4 ++-- docs/next/framework-features/rate-limiting/index.html | 4 ++-- docs/next/framework-features/rbac/index.html | 4 ++-- docs/next/getting-started/best-practices/index.html | 4 ++-- .../customized-laravel-components/index.html | 4 ++-- docs/next/getting-started/installation/index.html | 10 +++++----- docs/next/pacakges/documentation/index.html | 4 ++-- docs/next/pacakges/index.html | 4 ++-- docs/next/pacakges/localization/index.html | 4 ++-- docs/next/pacakges/social-authentication/index.html | 4 ++-- docs/next/prologue/contribution-guide/index.html | 4 ++-- docs/next/prologue/release-notes/index.html | 4 ++-- docs/next/prologue/upgrade-guide/index.html | 4 ++-- docs/next/security/authentication/index.html | 4 ++-- docs/next/security/authorization/index.html | 4 ++-- docs/next/security/email-varification/index.html | 4 ++-- docs/next/security/hash-id/index.html | 4 ++-- docs/next/security/password-reset/index.html | 4 ++-- docs/next/security/registration/index.html | 4 ++-- docs/next/tags/action/index.html | 4 ++-- docs/next/tags/api-versioning/index.html | 4 ++-- docs/next/tags/architecture/index.html | 4 ++-- docs/next/tags/authorization/index.html | 4 ++-- docs/next/tags/code-generator/index.html | 4 ++-- docs/next/tags/command/index.html | 4 ++-- docs/next/tags/component/index.html | 4 ++-- docs/next/tags/config/index.html | 4 ++-- docs/next/tags/container/index.html | 4 ++-- docs/next/tags/controller/index.html | 4 ++-- docs/next/tags/criteria/index.html | 4 ++-- docs/next/tags/etag/index.html | 4 ++-- docs/next/tags/event/index.html | 4 ++-- docs/next/tags/exception/index.html | 4 ++-- docs/next/tags/factory/index.html | 4 ++-- docs/next/tags/framework-feature/index.html | 4 ++-- docs/next/tags/helper/index.html | 4 ++-- docs/next/tags/index.html | 4 ++-- docs/next/tags/job/index.html | 4 ++-- docs/next/tags/lifecycle/index.html | 4 ++-- docs/next/tags/listener/index.html | 4 ++-- docs/next/tags/mail/index.html | 4 ++-- docs/next/tags/main-component/index.html | 4 ++-- docs/next/tags/middleware/index.html | 4 ++-- docs/next/tags/migration/index.html | 4 ++-- docs/next/tags/model/index.html | 4 ++-- docs/next/tags/notification/index.html | 4 ++-- docs/next/tags/optional-component/index.html | 4 ++-- docs/next/tags/policy/index.html | 4 ++-- docs/next/tags/porto/index.html | 4 ++-- docs/next/tags/profiler/index.html | 4 ++-- docs/next/tags/queue/index.html | 4 ++-- docs/next/tags/rate-limiting/index.html | 4 ++-- docs/next/tags/repository/index.html | 4 ++-- docs/next/tags/request/index.html | 4 ++-- docs/next/tags/response/index.html | 4 ++-- docs/next/tags/role-based-access-control/index.html | 4 ++-- docs/next/tags/route/index.html | 4 ++-- docs/next/tags/seeder/index.html | 4 ++-- docs/next/tags/service-provider/index.html | 4 ++-- docs/next/tags/sub-action/index.html | 4 ++-- docs/next/tags/task/index.html | 4 ++-- docs/next/tags/test/index.html | 4 ++-- docs/next/tags/testing/index.html | 4 ++-- docs/next/tags/transformer/index.html | 4 ++-- docs/next/tags/value/index.html | 4 ++-- docs/next/tags/view/index.html | 4 ++-- docs/pacakges/documentation/index.html | 4 ++-- docs/pacakges/index.html | 4 ++-- docs/pacakges/localization/index.html | 4 ++-- docs/pacakges/social-authentication/index.html | 4 ++-- docs/prologue/contribution-guide/index.html | 4 ++-- docs/prologue/release-notes/index.html | 4 ++-- docs/prologue/upgrade-guide/index.html | 4 ++-- docs/security/authentication/index.html | 4 ++-- docs/security/authorization/index.html | 4 ++-- docs/security/email-varification/index.html | 4 ++-- docs/security/hash-id/index.html | 4 ++-- docs/security/password-reset/index.html | 4 ++-- docs/security/registration/index.html | 4 ++-- docs/tags/action/index.html | 4 ++-- docs/tags/api-versioning/index.html | 4 ++-- docs/tags/architecture/index.html | 4 ++-- docs/tags/authorization/index.html | 4 ++-- docs/tags/code-generator/index.html | 4 ++-- docs/tags/command/index.html | 4 ++-- docs/tags/component/index.html | 4 ++-- docs/tags/config/index.html | 4 ++-- docs/tags/container/index.html | 4 ++-- docs/tags/controller/index.html | 4 ++-- docs/tags/criteria/index.html | 4 ++-- docs/tags/etag/index.html | 4 ++-- docs/tags/event/index.html | 4 ++-- docs/tags/exception/index.html | 4 ++-- docs/tags/factory/index.html | 4 ++-- docs/tags/framework-feature/index.html | 4 ++-- docs/tags/helper/index.html | 4 ++-- docs/tags/index.html | 4 ++-- docs/tags/job/index.html | 4 ++-- docs/tags/lifecycle/index.html | 4 ++-- docs/tags/listener/index.html | 4 ++-- docs/tags/mail/index.html | 4 ++-- docs/tags/main-component/index.html | 4 ++-- docs/tags/middleware/index.html | 4 ++-- docs/tags/migration/index.html | 4 ++-- docs/tags/model/index.html | 4 ++-- docs/tags/notification/index.html | 4 ++-- docs/tags/optional-component/index.html | 4 ++-- docs/tags/policy/index.html | 4 ++-- docs/tags/porto/index.html | 4 ++-- docs/tags/profiler/index.html | 4 ++-- docs/tags/queue/index.html | 4 ++-- docs/tags/rate-limiting/index.html | 4 ++-- docs/tags/repository/index.html | 4 ++-- docs/tags/request/index.html | 4 ++-- docs/tags/response/index.html | 4 ++-- docs/tags/role-based-access-control/index.html | 4 ++-- docs/tags/route/index.html | 4 ++-- docs/tags/seeder/index.html | 4 ++-- docs/tags/service-provider/index.html | 4 ++-- docs/tags/sub-action/index.html | 4 ++-- docs/tags/task/index.html | 4 ++-- docs/tags/test/index.html | 4 ++-- docs/tags/testing/index.html | 4 ++-- docs/tags/transformer/index.html | 4 ++-- docs/tags/value/index.html | 4 ++-- docs/tags/view/index.html | 4 ++-- index.html | 4 ++-- 412 files changed, 823 insertions(+), 823 deletions(-) delete mode 100644 assets/js/1f4f2990.6785e7f1.js create mode 100644 assets/js/1f4f2990.8bcc2ebe.js delete mode 100644 assets/js/6459b84b.257a7b0e.js create mode 100644 assets/js/6459b84b.a79374b0.js rename assets/js/{runtime~main.35c54bbc.js => runtime~main.54e3bf55.js} (99%) diff --git a/404.html b/404.html index c095d9f14..72da7f7c7 100644 --- a/404.html +++ b/404.html @@ -4,13 +4,13 @@ Page Not Found | Apiato - +
Skip to main content

Page Not Found

We could not find what you were looking for.

Please contact the owner of the site that linked you to the original URL and let them know their link is broken.

- + \ No newline at end of file diff --git a/assets/js/1f4f2990.6785e7f1.js b/assets/js/1f4f2990.6785e7f1.js deleted file mode 100644 index b2363be8a..000000000 --- a/assets/js/1f4f2990.6785e7f1.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkdocumentation=self.webpackChunkdocumentation||[]).push([[9160],{95788:(e,t,a)=>{a.d(t,{Iu:()=>u,yg:()=>y});var n=a(11504);function i(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function o(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,n)}return a}function r(e){for(var t=1;t=0||(i[a]=e[a]);return i}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(i[a]=e[a])}return i}var p=n.createContext({}),s=function(e){var t=n.useContext(p),a=t;return e&&(a="function"==typeof e?e(t):r(r({},t),e)),a},u=function(e){var t=s(e.components);return n.createElement(p.Provider,{value:t},e.children)},d="mdxType",c={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},g=n.forwardRef((function(e,t){var a=e.components,i=e.mdxType,o=e.originalType,p=e.parentName,u=l(e,["components","mdxType","originalType","parentName"]),d=s(a),g=i,y=d["".concat(p,".").concat(g)]||d[g]||c[g]||o;return a?n.createElement(y,r(r({ref:t},u),{},{components:a})):n.createElement(y,r({ref:t},u))}));function y(e,t){var a=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var o=a.length,r=new Array(o);r[0]=g;var l={};for(var p in t)hasOwnProperty.call(t,p)&&(l[p]=t[p]);l.originalType=e,l[d]="string"==typeof e?e:i,r[1]=l;for(var s=2;s{a.r(t),a.d(t,{assets:()=>s,contentTitle:()=>l,default:()=>g,frontMatter:()=>r,metadata:()=>p,toc:()=>u});var n=a(45072),i=(a(11504),a(95788)),o=a(25058);const r={sidebar_position:1,title:"Installation"},l=void 0,p={unversionedId:"getting-started/installation",id:"version-12.x/getting-started/installation",title:"Installation",description:"Your First Apiato Project",source:"@site/versioned_docs/version-12.x/getting-started/installation.mdx",sourceDirName:"getting-started",slug:"/getting-started/installation",permalink:"/docs/getting-started/installation",draft:!1,editUrl:"https://github.com/apiato/documentation/tree/master/versioned_docs/version-12.x/getting-started/installation.mdx",tags:[],version:"12.x",lastUpdatedBy:"Mohammad Alavi",lastUpdatedAt:1706267353,formattedLastUpdatedAt:"Jan 26, 2024",sidebarPosition:1,frontMatter:{sidebar_position:1,title:"Installation"},sidebar:"tutorialSidebar",previous:{title:"Contribution Guide",permalink:"/docs/prologue/contribution-guide"},next:{title:"Best Practices",permalink:"/docs/getting-started/best-practices"}},s={},u=[{value:"Your First Apiato Project",id:"your-first-apiato-project",level:2},{value:"Development Environment Setup",id:"development-environment-setup",level:2},{value:"Initial Configuration",id:"initial-configuration",level:2},{value:"Environment Based Configuration",id:"environment-based-configuration",level:3},{value:"Databases & Migrations",id:"databases--migrations",level:3},{value:"Default User, Roles & Permissions",id:"default-user-roles--permissions",level:4},{value:"Default User Credentials:",id:"default-user-credentials",level:4},{value:"Authentication Configuration",id:"authentication-configuration",level:3},{value:"Directory Configuration",id:"directory-configuration",level:3},{value:"Subdomain and API Version Prefix",id:"subdomain-and-api-version-prefix",level:3},{value:"Generating API Documentation",id:"generating-api-documentation",level:2},{value:"Let's Play",id:"lets-play",level:2},{value:"Web (Browser)",id:"web-browser",level:4},{value:"API (HTTP Client)",id:"api-http-client",level:4},{value:"Next Steps",id:"next-steps",level:2}],d={toc:u},c="wrapper";function g(e){let{components:t,...a}=e;return(0,i.yg)(c,(0,n.c)({},d,a,{components:t,mdxType:"MDXLayout"}),(0,i.yg)("h2",{id:"your-first-apiato-project"},"Your First Apiato Project"),(0,i.yg)("p",null,"Before creating your first Apiato project, you should ensure that your local machine has PHP and ",(0,i.yg)("a",{parentName:"p",href:"https://getcomposer.org/"},"Composer")," installed.\nIf you are developing on macOS, PHP and Composer can be installed via ",(0,i.yg)("a",{parentName:"p",href:"https://brew.sh/"},"Homebrew"),"."),(0,i.yg)("p",null,"After you have installed PHP and Composer, you may create a new Apiato project via the Composer create-project command:"),(0,i.yg)("pre",null,(0,i.yg)("code",{parentName:"pre"},"composer create-project apiato/apiato example-app\n")),(0,i.yg)("h2",{id:"development-environment-setup"},"Development Environment Setup"),(0,i.yg)("p",null,"You can run ",(0,i.yg)("strong",{parentName:"p"},"Apiato")," in any environment that you can run Laravel."),(0,i.yg)("admonition",{type:"tip"},(0,i.yg)("p",{parentName:"admonition"},"Visit ",(0,i.yg)("a",{parentName:"p",href:"https://laravel.com/docs/installation#laravel-and-docker"},"Laravel Installation")," for more details.")),(0,i.yg)("h2",{id:"initial-configuration"},"Initial Configuration"),(0,i.yg)("p",null,"All the configuration files for the Laravel framework are stored in the ",(0,i.yg)("inlineCode",{parentName:"p"},"config")," folder\nand all the configuration files for the Apiato framework are stored in ",(0,i.yg)("inlineCode",{parentName:"p"},"app/Ship/Configs"),".\nEach option is documented, so feel free to look through the files and get familiar with the options available to you."),(0,i.yg)("p",null,"Apiato needs almost no additional configuration out of the box.\nYou are free to get started developing!\nHowever, you may wish to review the ",(0,i.yg)("inlineCode",{parentName:"p"},"app/Ship/Configs/apiato.php")," file and its documentation.\nIt contains several options that you may wish to change according to your application."),(0,i.yg)("h3",{id:"environment-based-configuration"},"Environment Based Configuration"),(0,i.yg)("p",null,"Since many of Apiato configuration option values may vary\ndepending on whether your application is running on your local machine or on a production web server,\nmany important configuration values are defined using the ",(0,i.yg)("inlineCode",{parentName:"p"},".env")," file that exists at the root of your application."),(0,i.yg)("p",null,"Your ",(0,i.yg)("inlineCode",{parentName:"p"},".env")," file should not be committed to your application's source control,\nsince each developer / server using your application could require a different environment configuration.\nFurthermore, this would be a security risk in the event an intruder gains access to your source control repository,\nsince any sensitive credentials would get exposed."),(0,i.yg)("admonition",{type:"info"},(0,i.yg)("p",{parentName:"admonition"},"For more information about the ",(0,i.yg)("inlineCode",{parentName:"p"},".env")," file and environment based configuration,\ncheck out the Laravel full ",(0,i.yg)("a",{parentName:"p",href:"https://laravel.com/docs/configuration"},"configuration documentation"),".")),(0,i.yg)("h3",{id:"databases--migrations"},"Databases & Migrations"),(0,i.yg)("p",null,"Now that you have created your Apiato application, you probably want to store some data in a database.\nBy default,\nyour application's ",(0,i.yg)("inlineCode",{parentName:"p"},".env")," configuration file specifies\nthat Apiato will be interacting with a MySQL database and will access the database at ",(0,i.yg)("inlineCode",{parentName:"p"},"127.0.0.1"),".\nIf you are developing on macOS and need to install MySQL, Postgres,\nor Redis locally, you may find it convenient to utilize ",(0,i.yg)("inlineCode",{parentName:"p"},"DBngin"),"."),(0,i.yg)("p",null,"If you do not want to install MySQL or Postgres on your local machine,\nyou can always use a ",(0,i.yg)("a",{parentName:"p",href:"https://www.sqlite.org/index.html"},"SQLite")," database.\nSQLite is a small, fast, self-contained database engine.\nTo get started, create a SQLite database by creating an empty SQLite file.\nTypically, this file will exist within the database directory of your Apiato application:"),(0,i.yg)("pre",null,(0,i.yg)("code",{parentName:"pre"},"touch database/database.sqlite\n")),(0,i.yg)("p",null,"Next, update your ",(0,i.yg)("inlineCode",{parentName:"p"},".env")," configuration file to use Laravel sqlite database driver.\nYou may remove the other database configuration options:"),(0,i.yg)("pre",null,(0,i.yg)("code",{parentName:"pre",className:"language-diff"},"+ DB_CONNECTION=sqlite\n- DB_CONNECTION=mysql\n- DB_HOST=127.0.0.1\n- DB_PORT=3306\n- DB_DATABASE=homestead\n- DB_USERNAME=homestead\n- DB_PASSWORD=secret\n")),(0,i.yg)("p",null,"Once you have configured your SQLite database,\nyou may run your application's ",(0,i.yg)("a",{parentName:"p",href:"https://laravel.com/docs/migrations"},"database migrations"),",\nwhich will create your application's database tables:"),(0,i.yg)("pre",null,(0,i.yg)("code",{parentName:"pre"},"php artisan migrate\n")),(0,i.yg)("h4",{id:"default-user-roles--permissions"},"Default User, Roles & Permissions"),(0,i.yg)("p",null,"Apiato includes a default (Super Admin) user along with predefined roles and permissions.\nTo populate the database with these default values, you may execute the ",(0,i.yg)("inlineCode",{parentName:"p"},"db:seed")," command."),(0,i.yg)("pre",null,(0,i.yg)("code",{parentName:"pre"},"php artisan db:seed\n")),(0,i.yg)("h4",{id:"default-user-credentials"},"Default User Credentials:"),(0,i.yg)("ul",null,(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("span",null,"email: ",o.Q.C.G)),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("span",null,"password: ",o.Q.C.A))),(0,i.yg)("admonition",{type:"tip"},(0,i.yg)("p",{parentName:"admonition"},"You can create a new admin user using the ",(0,i.yg)("inlineCode",{parentName:"p"},"apiato:create:admin")," interactive command:"),(0,i.yg)("pre",{parentName:"admonition"},(0,i.yg)("code",{parentName:"pre"},"php artisan apiato:create:admin\n"))),(0,i.yg)("h3",{id:"authentication-configuration"},"Authentication Configuration"),(0,i.yg)("p",null,"Visit ",(0,i.yg)("a",{parentName:"p",href:"/docs/security/authentication"},"Authentication")," for more details."),(0,i.yg)("h3",{id:"directory-configuration"},"Directory Configuration"),(0,i.yg)("p",null,'Apiato should always be served out of the root of the "web directory" configured for your web server.\nYou should not attempt to serve a Apiato application out of a subdirectory of the "web directory".\nAttempting to do so could expose sensitive files present within your application.'),(0,i.yg)("h3",{id:"subdomain-and-api-version-prefix"},"Subdomain and API Version Prefix"),(0,i.yg)("p",null,"By default, Apiato uses ",(0,i.yg)("inlineCode",{parentName:"p"},"api")," as a subdomain for all endpoints and adds only the API version as a prefix,\nresulting in URLs like ",(0,i.yg)("inlineCode",{parentName:"p"},"api.apiato.test/v1"),".\nHowever, you can change this behavior."),(0,i.yg)("p",null,"For example, if you'd like to achieve urls like ",(0,i.yg)("inlineCode",{parentName:"p"},"apiato.test/api/"),", follow these steps:"),(0,i.yg)("ol",null,(0,i.yg)("li",{parentName:"ol"},"Open your ",(0,i.yg)("inlineCode",{parentName:"li"},".env")," file and modify the API domain by updating the ",(0,i.yg)("inlineCode",{parentName:"li"},"API_URL")," value from ",(0,i.yg)("inlineCode",{parentName:"li"},"http://api.apiato.test")," to ",(0,i.yg)("inlineCode",{parentName:"li"},"http://apiato.test")," to remove the subdomain."),(0,i.yg)("li",{parentName:"ol"},"In the ",(0,i.yg)("inlineCode",{parentName:"li"},"app/Ship/Configs/apiato.php")," configuration file:",(0,i.yg)("ul",{parentName:"li"},(0,i.yg)("li",{parentName:"ul"},"Set the ",(0,i.yg)("inlineCode",{parentName:"li"},"prefix")," to ",(0,i.yg)("inlineCode",{parentName:"li"},"api/"),"."),(0,i.yg)("li",{parentName:"ul"},"Set ",(0,i.yg)("inlineCode",{parentName:"li"},"enable_version_prefix")," to ",(0,i.yg)("inlineCode",{parentName:"li"},"false"),".")))),(0,i.yg)("h2",{id:"generating-api-documentation"},"Generating API Documentation"),(0,i.yg)("p",null,"Apiato includes a convenient ",(0,i.yg)("a",{parentName:"p",href:"/docs/pacakges/documentation"},"Documentation Generator")," package that utilizes ",(0,i.yg)("a",{parentName:"p",href:"https://apidocjs.com/"},"ApiDocJs")," for API documentation generation."),(0,i.yg)("p",null,"To get started, install ApiDocJs using NPM or your preferred dependency manager:"),(0,i.yg)("pre",null,(0,i.yg)("code",{parentName:"pre"},"npm install\n")),(0,i.yg)("p",null,"Next, generate the API documentation by executing the following command:"),(0,i.yg)("pre",null,(0,i.yg)("code",{parentName:"pre"},"php artisan apiato:apidoc\n")),(0,i.yg)("h2",{id:"lets-play"},"Let's Play"),(0,i.yg)("p",null,"To witness Apiato in action,\nassuming you are using the default ",(0,i.yg)("a",{parentName:"p",href:"#subdomain-and-api-version-prefix"},"Subdomain and API Version Prefix")," configuration,\nyou should be able to access the following URLs and see the following results:"),(0,i.yg)("h4",{id:"web-browser"},"Web (Browser)"),(0,i.yg)("ul",null,(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"http://apiato.test"},"http://apiato.test")," -> Apiato welcome page.")),(0,i.yg)("h4",{id:"api-http-client"},"API (HTTP Client)"),(0,i.yg)("ul",null,(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"http://api.apiato.test"},"http://api.apiato.test")," -> ",(0,i.yg)("inlineCode",{parentName:"li"},'"Welcome to Apiato"')),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"http://api.apiato.test/v1"},"http://api.apiato.test/v1")," -> ",(0,i.yg)("inlineCode",{parentName:"li"},'"Welcome to Apiato (API V1)"'))),(0,i.yg)("h2",{id:"next-steps"},"Next Steps"),(0,i.yg)("p",null,"Now that you have created your Apiato project, you may be wondering what to learn next.\nIf you're looking for a place to start, you should check out the following resources:"),(0,i.yg)("ul",null,(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"/docs/architecture-concepts/"},"Apiato Architecture")),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"/docs/getting-started/customized-laravel-components"},"Customized Laravel Components")),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"/docs/framework-features/"},"Framework Features")),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"/docs/pacakges/"},"Container Installer"))))}g.isMDXComponent=!0},25058:e=>{e.exports=JSON.parse('{"Q":{"G":{"m":"http://api.apiato.test/v1"},"C":{"G":"admin@admin.com","A":"admin"}}}')}}]); \ No newline at end of file diff --git a/assets/js/1f4f2990.8bcc2ebe.js b/assets/js/1f4f2990.8bcc2ebe.js new file mode 100644 index 000000000..e7890cb33 --- /dev/null +++ b/assets/js/1f4f2990.8bcc2ebe.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocumentation=self.webpackChunkdocumentation||[]).push([[9160],{95788:(e,t,a)=>{a.d(t,{Iu:()=>u,yg:()=>y});var n=a(11504);function i(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function o(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,n)}return a}function r(e){for(var t=1;t=0||(i[a]=e[a]);return i}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(i[a]=e[a])}return i}var p=n.createContext({}),s=function(e){var t=n.useContext(p),a=t;return e&&(a="function"==typeof e?e(t):r(r({},t),e)),a},u=function(e){var t=s(e.components);return n.createElement(p.Provider,{value:t},e.children)},d="mdxType",c={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},g=n.forwardRef((function(e,t){var a=e.components,i=e.mdxType,o=e.originalType,p=e.parentName,u=l(e,["components","mdxType","originalType","parentName"]),d=s(a),g=i,y=d["".concat(p,".").concat(g)]||d[g]||c[g]||o;return a?n.createElement(y,r(r({ref:t},u),{},{components:a})):n.createElement(y,r({ref:t},u))}));function y(e,t){var a=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var o=a.length,r=new Array(o);r[0]=g;var l={};for(var p in t)hasOwnProperty.call(t,p)&&(l[p]=t[p]);l.originalType=e,l[d]="string"==typeof e?e:i,r[1]=l;for(var s=2;s{a.r(t),a.d(t,{assets:()=>s,contentTitle:()=>l,default:()=>g,frontMatter:()=>r,metadata:()=>p,toc:()=>u});var n=a(45072),i=(a(11504),a(95788)),o=a(25058);const r={sidebar_position:1,title:"Installation"},l=void 0,p={unversionedId:"getting-started/installation",id:"version-12.x/getting-started/installation",title:"Installation",description:"Your First Apiato Project",source:"@site/versioned_docs/version-12.x/getting-started/installation.mdx",sourceDirName:"getting-started",slug:"/getting-started/installation",permalink:"/docs/getting-started/installation",draft:!1,editUrl:"https://github.com/apiato/documentation/tree/master/versioned_docs/version-12.x/getting-started/installation.mdx",tags:[],version:"12.x",lastUpdatedBy:"Mohammad Alavi",lastUpdatedAt:1707396139,formattedLastUpdatedAt:"Feb 8, 2024",sidebarPosition:1,frontMatter:{sidebar_position:1,title:"Installation"},sidebar:"tutorialSidebar",previous:{title:"Contribution Guide",permalink:"/docs/prologue/contribution-guide"},next:{title:"Best Practices",permalink:"/docs/getting-started/best-practices"}},s={},u=[{value:"Your First Apiato Project",id:"your-first-apiato-project",level:2},{value:"Development Environment Setup",id:"development-environment-setup",level:2},{value:"Initial Configuration",id:"initial-configuration",level:2},{value:"Environment Based Configuration",id:"environment-based-configuration",level:3},{value:"Databases & Migrations",id:"databases--migrations",level:3},{value:"Default User, Roles & Permissions",id:"default-user-roles--permissions",level:4},{value:"Default User Credentials:",id:"default-user-credentials",level:4},{value:"Authentication Configuration",id:"authentication-configuration",level:3},{value:"Directory Configuration",id:"directory-configuration",level:3},{value:"Subdomain and API Version Prefix",id:"subdomain-and-api-version-prefix",level:3},{value:"Generating API Documentation",id:"generating-api-documentation",level:2},{value:"Let's Play",id:"lets-play",level:2},{value:"Web (Browser)",id:"web-browser",level:4},{value:"API (HTTP Client)",id:"api-http-client",level:4},{value:"Next Steps",id:"next-steps",level:2}],d={toc:u},c="wrapper";function g(e){let{components:t,...a}=e;return(0,i.yg)(c,(0,n.c)({},d,a,{components:t,mdxType:"MDXLayout"}),(0,i.yg)("h2",{id:"your-first-apiato-project"},"Your First Apiato Project"),(0,i.yg)("p",null,"Before creating your first Apiato project, you should ensure that your local machine has PHP and ",(0,i.yg)("a",{parentName:"p",href:"https://getcomposer.org/"},"Composer")," installed.\nIf you are developing on macOS, PHP and Composer can be installed via ",(0,i.yg)("a",{parentName:"p",href:"https://brew.sh/"},"Homebrew"),"."),(0,i.yg)("p",null,"After you have installed PHP and Composer, you may create a new Apiato project via the Composer create-project command:"),(0,i.yg)("pre",null,(0,i.yg)("code",{parentName:"pre"},"composer create-project apiato/apiato example-app --no-scripts\n")),(0,i.yg)("h2",{id:"development-environment-setup"},"Development Environment Setup"),(0,i.yg)("p",null,"You can run ",(0,i.yg)("strong",{parentName:"p"},"Apiato")," in any environment that you can run Laravel."),(0,i.yg)("admonition",{type:"tip"},(0,i.yg)("p",{parentName:"admonition"},"Visit ",(0,i.yg)("a",{parentName:"p",href:"https://laravel.com/docs/installation#laravel-and-docker"},"Laravel Installation")," for more details.")),(0,i.yg)("h2",{id:"initial-configuration"},"Initial Configuration"),(0,i.yg)("p",null,"All the configuration files for the Laravel framework are stored in the ",(0,i.yg)("inlineCode",{parentName:"p"},"config")," folder\nand all the configuration files for the Apiato framework are stored in ",(0,i.yg)("inlineCode",{parentName:"p"},"app/Ship/Configs"),".\nEach option is documented, so feel free to look through the files and get familiar with the options available to you."),(0,i.yg)("p",null,"Apiato needs almost no additional configuration out of the box.\nYou are free to get started developing!\nHowever, you may wish to review the ",(0,i.yg)("inlineCode",{parentName:"p"},"app/Ship/Configs/apiato.php")," file and its documentation.\nIt contains several options that you may wish to change, according to your application."),(0,i.yg)("h3",{id:"environment-based-configuration"},"Environment Based Configuration"),(0,i.yg)("p",null,"Since many of Apiato configuration option values may vary\ndepending on whether your application is running on your local machine or on a production web server,\nmany important configuration values are defined using the ",(0,i.yg)("inlineCode",{parentName:"p"},".env")," file that exists at the root of your application."),(0,i.yg)("p",null,"Your ",(0,i.yg)("inlineCode",{parentName:"p"},".env")," file should not be committed to your application's source control,\nsince each developer / server using your application could require a different environment configuration.\nFurthermore, this would be a security risk in the event an intruder gains access to your source control repository,\nsince any sensitive credentials would get exposed."),(0,i.yg)("admonition",{type:"info"},(0,i.yg)("p",{parentName:"admonition"},"For more information about the ",(0,i.yg)("inlineCode",{parentName:"p"},".env")," file and environment based configuration,\ncheck out the Laravel full ",(0,i.yg)("a",{parentName:"p",href:"https://laravel.com/docs/configuration"},"configuration documentation"),".")),(0,i.yg)("h3",{id:"databases--migrations"},"Databases & Migrations"),(0,i.yg)("p",null,"Now that you have created your Apiato application, you probably want to store some data in a database.\nBy default,\nyour application's ",(0,i.yg)("inlineCode",{parentName:"p"},".env")," configuration file specifies\nthat Apiato will be interacting with a MySQL database and will access the database at ",(0,i.yg)("inlineCode",{parentName:"p"},"127.0.0.1"),".\nIf you are developing on macOS and need to install MySQL, Postgres,\nor Redis locally, you may find it convenient to utilize ",(0,i.yg)("inlineCode",{parentName:"p"},"DBngin"),"."),(0,i.yg)("p",null,"If you do not want to install MySQL or Postgres on your local machine,\nyou can always use a ",(0,i.yg)("a",{parentName:"p",href:"https://www.sqlite.org/index.html"},"SQLite")," database.\nSQLite is a small, fast, self-contained database engine.\nTo get started, create a SQLite database by creating an empty SQLite file.\nTypically, this file will exist within the database directory of your Apiato application:"),(0,i.yg)("pre",null,(0,i.yg)("code",{parentName:"pre"},"touch database/database.sqlite\n")),(0,i.yg)("p",null,"Next, update your ",(0,i.yg)("inlineCode",{parentName:"p"},".env")," configuration file to use Laravel sqlite database driver.\nYou may remove the other database configuration options:"),(0,i.yg)("pre",null,(0,i.yg)("code",{parentName:"pre",className:"language-diff"},"+ DB_CONNECTION=sqlite\n- DB_CONNECTION=mysql\n- DB_HOST=127.0.0.1\n- DB_PORT=3306\n- DB_DATABASE=homestead\n- DB_USERNAME=homestead\n- DB_PASSWORD=secret\n")),(0,i.yg)("p",null,"Once you have configured your SQLite database,\nyou may run your application's ",(0,i.yg)("a",{parentName:"p",href:"https://laravel.com/docs/migrations"},"database migrations"),",\nwhich will create your application's database tables:"),(0,i.yg)("pre",null,(0,i.yg)("code",{parentName:"pre"},"php artisan migrate\n")),(0,i.yg)("h4",{id:"default-user-roles--permissions"},"Default User, Roles & Permissions"),(0,i.yg)("p",null,"Apiato includes a default (Super Admin) user along with predefined roles and permissions.\nTo populate the database with these default values, you may execute the ",(0,i.yg)("inlineCode",{parentName:"p"},"db:seed")," command."),(0,i.yg)("pre",null,(0,i.yg)("code",{parentName:"pre"},"php artisan db:seed\n")),(0,i.yg)("h4",{id:"default-user-credentials"},"Default User Credentials:"),(0,i.yg)("ul",null,(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("span",null,"email: ",o.Q.C.G)),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("span",null,"password: ",o.Q.C.A))),(0,i.yg)("admonition",{type:"tip"},(0,i.yg)("p",{parentName:"admonition"},"You can create a new admin user using the ",(0,i.yg)("inlineCode",{parentName:"p"},"apiato:create:admin")," interactive command:"),(0,i.yg)("pre",{parentName:"admonition"},(0,i.yg)("code",{parentName:"pre"},"php artisan apiato:create:admin\n"))),(0,i.yg)("h3",{id:"authentication-configuration"},"Authentication Configuration"),(0,i.yg)("p",null,"Visit ",(0,i.yg)("a",{parentName:"p",href:"/docs/security/authentication"},"Authentication")," for more details."),(0,i.yg)("h3",{id:"directory-configuration"},"Directory Configuration"),(0,i.yg)("p",null,'Apiato should always be served out of the root of the "web directory" configured for your web server.\nYou should not attempt to serve a Apiato application out of a subdirectory of the "web directory".\nAttempting to do so could expose sensitive files present within your application.'),(0,i.yg)("h3",{id:"subdomain-and-api-version-prefix"},"Subdomain and API Version Prefix"),(0,i.yg)("p",null,"By default, Apiato uses ",(0,i.yg)("inlineCode",{parentName:"p"},"api")," as a subdomain for all endpoints and adds only the API version as a prefix,\nresulting in URLs like ",(0,i.yg)("inlineCode",{parentName:"p"},"api.apiato.test/v1"),".\nHowever, you can change this behavior."),(0,i.yg)("p",null,"For example, if you'd like to achieve urls like ",(0,i.yg)("inlineCode",{parentName:"p"},"apiato.test/api/"),", follow these steps:"),(0,i.yg)("ol",null,(0,i.yg)("li",{parentName:"ol"},"Open your ",(0,i.yg)("inlineCode",{parentName:"li"},".env")," file and modify the API domain by updating the ",(0,i.yg)("inlineCode",{parentName:"li"},"API_URL")," value from ",(0,i.yg)("inlineCode",{parentName:"li"},"http://api.apiato.test")," to ",(0,i.yg)("inlineCode",{parentName:"li"},"http://apiato.test")," to remove the subdomain."),(0,i.yg)("li",{parentName:"ol"},"In the ",(0,i.yg)("inlineCode",{parentName:"li"},"app/Ship/Configs/apiato.php")," configuration file:",(0,i.yg)("ul",{parentName:"li"},(0,i.yg)("li",{parentName:"ul"},"Set the ",(0,i.yg)("inlineCode",{parentName:"li"},"prefix")," to ",(0,i.yg)("inlineCode",{parentName:"li"},"api/"),"."),(0,i.yg)("li",{parentName:"ul"},"Set ",(0,i.yg)("inlineCode",{parentName:"li"},"enable_version_prefix")," to ",(0,i.yg)("inlineCode",{parentName:"li"},"false"),".")))),(0,i.yg)("h2",{id:"generating-api-documentation"},"Generating API Documentation"),(0,i.yg)("p",null,"Apiato includes a convenient ",(0,i.yg)("a",{parentName:"p",href:"/docs/pacakges/documentation"},"Documentation Generator")," package that utilizes ",(0,i.yg)("a",{parentName:"p",href:"https://apidocjs.com/"},"ApiDocJs")," for API documentation generation."),(0,i.yg)("p",null,"To get started, install ApiDocJs using NPM or your preferred dependency manager:"),(0,i.yg)("pre",null,(0,i.yg)("code",{parentName:"pre"},"npm install\n")),(0,i.yg)("p",null,"Next, generate the API documentation by executing the following command:"),(0,i.yg)("pre",null,(0,i.yg)("code",{parentName:"pre"},"php artisan apiato:apidoc\n")),(0,i.yg)("h2",{id:"lets-play"},"Let's Play"),(0,i.yg)("p",null,"To witness Apiato in action,\nassuming you are using the default ",(0,i.yg)("a",{parentName:"p",href:"#subdomain-and-api-version-prefix"},"Subdomain and API Version Prefix")," configuration,\nyou should be able to access the following URLs and see the following results:"),(0,i.yg)("h4",{id:"web-browser"},"Web (Browser)"),(0,i.yg)("ul",null,(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"http://apiato.test"},"http://apiato.test")," -> Apiato welcome page.")),(0,i.yg)("h4",{id:"api-http-client"},"API (HTTP Client)"),(0,i.yg)("ul",null,(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"http://api.apiato.test"},"http://api.apiato.test")," -> ",(0,i.yg)("inlineCode",{parentName:"li"},'"Welcome to Apiato"')),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"http://api.apiato.test/v1"},"http://api.apiato.test/v1")," -> ",(0,i.yg)("inlineCode",{parentName:"li"},'"Welcome to Apiato (API V1)"'))),(0,i.yg)("h2",{id:"next-steps"},"Next Steps"),(0,i.yg)("p",null,"Now that you have created your Apiato project, you may be wondering what to learn next.\nIf you're looking for a place to start, you should check out the following resources:"),(0,i.yg)("ul",null,(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"/docs/architecture-concepts/"},"Apiato Architecture")),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"/docs/getting-started/customized-laravel-components"},"Customized Laravel Components")),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"/docs/framework-features/"},"Framework Features")),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"/docs/pacakges/"},"Container Installer"))))}g.isMDXComponent=!0},25058:e=>{e.exports=JSON.parse('{"Q":{"G":{"m":"http://api.apiato.test/v1"},"C":{"G":"admin@admin.com","A":"admin"}}}')}}]); \ No newline at end of file diff --git a/assets/js/6459b84b.257a7b0e.js b/assets/js/6459b84b.257a7b0e.js deleted file mode 100644 index 18d148ce6..000000000 --- a/assets/js/6459b84b.257a7b0e.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkdocumentation=self.webpackChunkdocumentation||[]).push([[2280],{95788:(e,t,a)=>{a.d(t,{Iu:()=>u,yg:()=>y});var n=a(11504);function i(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function o(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,n)}return a}function r(e){for(var t=1;t=0||(i[a]=e[a]);return i}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(i[a]=e[a])}return i}var p=n.createContext({}),s=function(e){var t=n.useContext(p),a=t;return e&&(a="function"==typeof e?e(t):r(r({},t),e)),a},u=function(e){var t=s(e.components);return n.createElement(p.Provider,{value:t},e.children)},d="mdxType",c={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},g=n.forwardRef((function(e,t){var a=e.components,i=e.mdxType,o=e.originalType,p=e.parentName,u=l(e,["components","mdxType","originalType","parentName"]),d=s(a),g=i,y=d["".concat(p,".").concat(g)]||d[g]||c[g]||o;return a?n.createElement(y,r(r({ref:t},u),{},{components:a})):n.createElement(y,r({ref:t},u))}));function y(e,t){var a=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var o=a.length,r=new Array(o);r[0]=g;var l={};for(var p in t)hasOwnProperty.call(t,p)&&(l[p]=t[p]);l.originalType=e,l[d]="string"==typeof e?e:i,r[1]=l;for(var s=2;s{a.r(t),a.d(t,{assets:()=>s,contentTitle:()=>l,default:()=>g,frontMatter:()=>r,metadata:()=>p,toc:()=>u});var n=a(45072),i=(a(11504),a(95788)),o=a(25058);const r={sidebar_position:1,title:"Installation"},l=void 0,p={unversionedId:"getting-started/installation",id:"getting-started/installation",title:"Installation",description:"Your First Apiato Project",source:"@site/docs/getting-started/installation.mdx",sourceDirName:"getting-started",slug:"/getting-started/installation",permalink:"/docs/next/getting-started/installation",draft:!1,editUrl:"https://github.com/apiato/documentation/tree/master/docs/getting-started/installation.mdx",tags:[],version:"current",lastUpdatedBy:"Mohammad Alavi",lastUpdatedAt:1706267353,formattedLastUpdatedAt:"Jan 26, 2024",sidebarPosition:1,frontMatter:{sidebar_position:1,title:"Installation"},sidebar:"tutorialSidebar",previous:{title:"Contribution Guide",permalink:"/docs/next/prologue/contribution-guide"},next:{title:"Best Practices",permalink:"/docs/next/getting-started/best-practices"}},s={},u=[{value:"Your First Apiato Project",id:"your-first-apiato-project",level:2},{value:"Development Environment Setup",id:"development-environment-setup",level:2},{value:"Initial Configuration",id:"initial-configuration",level:2},{value:"Environment Based Configuration",id:"environment-based-configuration",level:3},{value:"Databases & Migrations",id:"databases--migrations",level:3},{value:"Default User, Roles & Permissions",id:"default-user-roles--permissions",level:4},{value:"Default User Credentials:",id:"default-user-credentials",level:4},{value:"Authentication Configuration",id:"authentication-configuration",level:3},{value:"Directory Configuration",id:"directory-configuration",level:3},{value:"Subdomain and API Version Prefix",id:"subdomain-and-api-version-prefix",level:3},{value:"Generating API Documentation",id:"generating-api-documentation",level:2},{value:"Let's Play",id:"lets-play",level:2},{value:"Web (Browser)",id:"web-browser",level:4},{value:"API (HTTP Client)",id:"api-http-client",level:4},{value:"Next Steps",id:"next-steps",level:2}],d={toc:u},c="wrapper";function g(e){let{components:t,...a}=e;return(0,i.yg)(c,(0,n.c)({},d,a,{components:t,mdxType:"MDXLayout"}),(0,i.yg)("h2",{id:"your-first-apiato-project"},"Your First Apiato Project"),(0,i.yg)("p",null,"Before creating your first Apiato project, you should ensure that your local machine has PHP and ",(0,i.yg)("a",{parentName:"p",href:"https://getcomposer.org/"},"Composer")," installed.\nIf you are developing on macOS, PHP and Composer can be installed via ",(0,i.yg)("a",{parentName:"p",href:"https://brew.sh/"},"Homebrew"),"."),(0,i.yg)("p",null,"After you have installed PHP and Composer, you may create a new Apiato project via the Composer create-project command:"),(0,i.yg)("pre",null,(0,i.yg)("code",{parentName:"pre"},"composer create-project apiato/apiato example-app\n")),(0,i.yg)("h2",{id:"development-environment-setup"},"Development Environment Setup"),(0,i.yg)("p",null,"You can run ",(0,i.yg)("strong",{parentName:"p"},"Apiato")," in any environment that you can run Laravel."),(0,i.yg)("admonition",{type:"tip"},(0,i.yg)("p",{parentName:"admonition"},"Visit ",(0,i.yg)("a",{parentName:"p",href:"https://laravel.com/docs/installation#laravel-and-docker"},"Laravel Installation")," for more details.")),(0,i.yg)("h2",{id:"initial-configuration"},"Initial Configuration"),(0,i.yg)("p",null,"All the configuration files for the Laravel framework are stored in the ",(0,i.yg)("inlineCode",{parentName:"p"},"config")," folder\nand all the configuration files for the Apiato framework are stored in ",(0,i.yg)("inlineCode",{parentName:"p"},"app/Ship/Configs"),".\nEach option is documented, so feel free to look through the files and get familiar with the options available to you."),(0,i.yg)("p",null,"Apiato needs almost no additional configuration out of the box.\nYou are free to get started developing!\nHowever, you may wish to review the ",(0,i.yg)("inlineCode",{parentName:"p"},"app/Ship/Configs/apiato.php")," file and its documentation.\nIt contains several options that you may wish to change according to your application."),(0,i.yg)("h3",{id:"environment-based-configuration"},"Environment Based Configuration"),(0,i.yg)("p",null,"Since many of Apiato configuration option values may vary\ndepending on whether your application is running on your local machine or on a production web server,\nmany important configuration values are defined using the ",(0,i.yg)("inlineCode",{parentName:"p"},".env")," file that exists at the root of your application."),(0,i.yg)("p",null,"Your ",(0,i.yg)("inlineCode",{parentName:"p"},".env")," file should not be committed to your application's source control,\nsince each developer / server using your application could require a different environment configuration.\nFurthermore, this would be a security risk in the event an intruder gains access to your source control repository,\nsince any sensitive credentials would get exposed."),(0,i.yg)("admonition",{type:"info"},(0,i.yg)("p",{parentName:"admonition"},"For more information about the ",(0,i.yg)("inlineCode",{parentName:"p"},".env")," file and environment based configuration,\ncheck out the Laravel full ",(0,i.yg)("a",{parentName:"p",href:"https://laravel.com/docs/configuration"},"configuration documentation"),".")),(0,i.yg)("h3",{id:"databases--migrations"},"Databases & Migrations"),(0,i.yg)("p",null,"Now that you have created your Apiato application, you probably want to store some data in a database.\nBy default,\nyour application's ",(0,i.yg)("inlineCode",{parentName:"p"},".env")," configuration file specifies\nthat Apiato will be interacting with a MySQL database and will access the database at ",(0,i.yg)("inlineCode",{parentName:"p"},"127.0.0.1"),".\nIf you are developing on macOS and need to install MySQL, Postgres,\nor Redis locally, you may find it convenient to utilize ",(0,i.yg)("inlineCode",{parentName:"p"},"DBngin"),"."),(0,i.yg)("p",null,"If you do not want to install MySQL or Postgres on your local machine,\nyou can always use a ",(0,i.yg)("a",{parentName:"p",href:"https://www.sqlite.org/index.html"},"SQLite")," database.\nSQLite is a small, fast, self-contained database engine.\nTo get started, create a SQLite database by creating an empty SQLite file.\nTypically, this file will exist within the database directory of your Apiato application:"),(0,i.yg)("pre",null,(0,i.yg)("code",{parentName:"pre"},"touch database/database.sqlite\n")),(0,i.yg)("p",null,"Next, update your ",(0,i.yg)("inlineCode",{parentName:"p"},".env")," configuration file to use Laravel sqlite database driver.\nYou may remove the other database configuration options:"),(0,i.yg)("pre",null,(0,i.yg)("code",{parentName:"pre",className:"language-diff"},"+ DB_CONNECTION=sqlite\n- DB_CONNECTION=mysql\n- DB_HOST=127.0.0.1\n- DB_PORT=3306\n- DB_DATABASE=homestead\n- DB_USERNAME=homestead\n- DB_PASSWORD=secret\n")),(0,i.yg)("p",null,"Once you have configured your SQLite database,\nyou may run your application's ",(0,i.yg)("a",{parentName:"p",href:"https://laravel.com/docs/migrations"},"database migrations"),",\nwhich will create your application's database tables:"),(0,i.yg)("pre",null,(0,i.yg)("code",{parentName:"pre"},"php artisan migrate\n")),(0,i.yg)("h4",{id:"default-user-roles--permissions"},"Default User, Roles & Permissions"),(0,i.yg)("p",null,"Apiato includes a default (Super Admin) user along with predefined roles and permissions.\nTo populate the database with these default values, you may execute the ",(0,i.yg)("inlineCode",{parentName:"p"},"db:seed")," command."),(0,i.yg)("pre",null,(0,i.yg)("code",{parentName:"pre"},"php artisan db:seed\n")),(0,i.yg)("h4",{id:"default-user-credentials"},"Default User Credentials:"),(0,i.yg)("ul",null,(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("span",null,"email: ",o.Q.C.G)),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("span",null,"password: ",o.Q.C.A))),(0,i.yg)("admonition",{type:"tip"},(0,i.yg)("p",{parentName:"admonition"},"You can create a new admin user using the ",(0,i.yg)("inlineCode",{parentName:"p"},"apiato:create:admin")," interactive command:"),(0,i.yg)("pre",{parentName:"admonition"},(0,i.yg)("code",{parentName:"pre"},"php artisan apiato:create:admin\n"))),(0,i.yg)("h3",{id:"authentication-configuration"},"Authentication Configuration"),(0,i.yg)("p",null,"Visit ",(0,i.yg)("a",{parentName:"p",href:"/docs/next/security/authentication"},"Authentication")," for more details."),(0,i.yg)("h3",{id:"directory-configuration"},"Directory Configuration"),(0,i.yg)("p",null,'Apiato should always be served out of the root of the "web directory" configured for your web server.\nYou should not attempt to serve a Apiato application out of a subdirectory of the "web directory".\nAttempting to do so could expose sensitive files present within your application.'),(0,i.yg)("h3",{id:"subdomain-and-api-version-prefix"},"Subdomain and API Version Prefix"),(0,i.yg)("p",null,"By default, Apiato uses ",(0,i.yg)("inlineCode",{parentName:"p"},"api")," as a subdomain for all endpoints and adds only the API version as a prefix,\nresulting in URLs like ",(0,i.yg)("inlineCode",{parentName:"p"},"api.apiato.test/v1"),".\nHowever, you can change this behavior."),(0,i.yg)("p",null,"For example, if you'd like to achieve urls like ",(0,i.yg)("inlineCode",{parentName:"p"},"apiato.test/api/"),", follow these steps:"),(0,i.yg)("ol",null,(0,i.yg)("li",{parentName:"ol"},"Open your ",(0,i.yg)("inlineCode",{parentName:"li"},".env")," file and modify the API domain by updating the ",(0,i.yg)("inlineCode",{parentName:"li"},"API_URL")," value from ",(0,i.yg)("inlineCode",{parentName:"li"},"http://api.apiato.test")," to ",(0,i.yg)("inlineCode",{parentName:"li"},"http://apiato.test")," to remove the subdomain."),(0,i.yg)("li",{parentName:"ol"},"In the ",(0,i.yg)("inlineCode",{parentName:"li"},"app/Ship/Configs/apiato.php")," configuration file:",(0,i.yg)("ul",{parentName:"li"},(0,i.yg)("li",{parentName:"ul"},"Set the ",(0,i.yg)("inlineCode",{parentName:"li"},"prefix")," to ",(0,i.yg)("inlineCode",{parentName:"li"},"api/"),"."),(0,i.yg)("li",{parentName:"ul"},"Set ",(0,i.yg)("inlineCode",{parentName:"li"},"enable_version_prefix")," to ",(0,i.yg)("inlineCode",{parentName:"li"},"false"),".")))),(0,i.yg)("h2",{id:"generating-api-documentation"},"Generating API Documentation"),(0,i.yg)("p",null,"Apiato includes a convenient ",(0,i.yg)("a",{parentName:"p",href:"/docs/next/pacakges/documentation"},"Documentation Generator")," package that utilizes ",(0,i.yg)("a",{parentName:"p",href:"https://apidocjs.com/"},"ApiDocJs")," for API documentation generation."),(0,i.yg)("p",null,"To get started, install ApiDocJs using NPM or your preferred dependency manager:"),(0,i.yg)("pre",null,(0,i.yg)("code",{parentName:"pre"},"npm install\n")),(0,i.yg)("p",null,"Next, generate the API documentation by executing the following command:"),(0,i.yg)("pre",null,(0,i.yg)("code",{parentName:"pre"},"php artisan apiato:apidoc\n")),(0,i.yg)("h2",{id:"lets-play"},"Let's Play"),(0,i.yg)("p",null,"To witness Apiato in action,\nassuming you are using the default ",(0,i.yg)("a",{parentName:"p",href:"#subdomain-and-api-version-prefix"},"Subdomain and API Version Prefix")," configuration,\nyou should be able to access the following URLs and see the following results:"),(0,i.yg)("h4",{id:"web-browser"},"Web (Browser)"),(0,i.yg)("ul",null,(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"http://apiato.test"},"http://apiato.test")," -> Apiato welcome page.")),(0,i.yg)("h4",{id:"api-http-client"},"API (HTTP Client)"),(0,i.yg)("ul",null,(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"http://api.apiato.test"},"http://api.apiato.test")," -> ",(0,i.yg)("inlineCode",{parentName:"li"},'"Welcome to Apiato"')),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"http://api.apiato.test/v1"},"http://api.apiato.test/v1")," -> ",(0,i.yg)("inlineCode",{parentName:"li"},'"Welcome to Apiato (API V1)"'))),(0,i.yg)("h2",{id:"next-steps"},"Next Steps"),(0,i.yg)("p",null,"Now that you have created your Apiato project, you may be wondering what to learn next.\nIf you're looking for a place to start, you should check out the following resources:"),(0,i.yg)("ul",null,(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"/docs/next/architecture-concepts/"},"Apiato Architecture")),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"/docs/next/getting-started/customized-laravel-components"},"Customized Laravel Components")),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"/docs/next/framework-features/"},"Framework Features")),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"/docs/next/pacakges/"},"Container Installer"))))}g.isMDXComponent=!0},25058:e=>{e.exports=JSON.parse('{"Q":{"G":{"m":"http://api.apiato.test/v1"},"C":{"G":"admin@admin.com","A":"admin"}}}')}}]); \ No newline at end of file diff --git a/assets/js/6459b84b.a79374b0.js b/assets/js/6459b84b.a79374b0.js new file mode 100644 index 000000000..2a756bcfa --- /dev/null +++ b/assets/js/6459b84b.a79374b0.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocumentation=self.webpackChunkdocumentation||[]).push([[2280],{95788:(e,t,a)=>{a.d(t,{Iu:()=>u,yg:()=>y});var n=a(11504);function i(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function o(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,n)}return a}function r(e){for(var t=1;t=0||(i[a]=e[a]);return i}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(i[a]=e[a])}return i}var p=n.createContext({}),s=function(e){var t=n.useContext(p),a=t;return e&&(a="function"==typeof e?e(t):r(r({},t),e)),a},u=function(e){var t=s(e.components);return n.createElement(p.Provider,{value:t},e.children)},d="mdxType",c={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},g=n.forwardRef((function(e,t){var a=e.components,i=e.mdxType,o=e.originalType,p=e.parentName,u=l(e,["components","mdxType","originalType","parentName"]),d=s(a),g=i,y=d["".concat(p,".").concat(g)]||d[g]||c[g]||o;return a?n.createElement(y,r(r({ref:t},u),{},{components:a})):n.createElement(y,r({ref:t},u))}));function y(e,t){var a=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var o=a.length,r=new Array(o);r[0]=g;var l={};for(var p in t)hasOwnProperty.call(t,p)&&(l[p]=t[p]);l.originalType=e,l[d]="string"==typeof e?e:i,r[1]=l;for(var s=2;s{a.r(t),a.d(t,{assets:()=>s,contentTitle:()=>l,default:()=>g,frontMatter:()=>r,metadata:()=>p,toc:()=>u});var n=a(45072),i=(a(11504),a(95788)),o=a(25058);const r={sidebar_position:1,title:"Installation"},l=void 0,p={unversionedId:"getting-started/installation",id:"getting-started/installation",title:"Installation",description:"Your First Apiato Project",source:"@site/docs/getting-started/installation.mdx",sourceDirName:"getting-started",slug:"/getting-started/installation",permalink:"/docs/next/getting-started/installation",draft:!1,editUrl:"https://github.com/apiato/documentation/tree/master/docs/getting-started/installation.mdx",tags:[],version:"current",lastUpdatedBy:"Mohammad Alavi",lastUpdatedAt:1707396139,formattedLastUpdatedAt:"Feb 8, 2024",sidebarPosition:1,frontMatter:{sidebar_position:1,title:"Installation"},sidebar:"tutorialSidebar",previous:{title:"Contribution Guide",permalink:"/docs/next/prologue/contribution-guide"},next:{title:"Best Practices",permalink:"/docs/next/getting-started/best-practices"}},s={},u=[{value:"Your First Apiato Project",id:"your-first-apiato-project",level:2},{value:"Development Environment Setup",id:"development-environment-setup",level:2},{value:"Initial Configuration",id:"initial-configuration",level:2},{value:"Environment Based Configuration",id:"environment-based-configuration",level:3},{value:"Databases & Migrations",id:"databases--migrations",level:3},{value:"Default User, Roles & Permissions",id:"default-user-roles--permissions",level:4},{value:"Default User Credentials:",id:"default-user-credentials",level:4},{value:"Authentication Configuration",id:"authentication-configuration",level:3},{value:"Directory Configuration",id:"directory-configuration",level:3},{value:"Subdomain and API Version Prefix",id:"subdomain-and-api-version-prefix",level:3},{value:"Generating API Documentation",id:"generating-api-documentation",level:2},{value:"Let's Play",id:"lets-play",level:2},{value:"Web (Browser)",id:"web-browser",level:4},{value:"API (HTTP Client)",id:"api-http-client",level:4},{value:"Next Steps",id:"next-steps",level:2}],d={toc:u},c="wrapper";function g(e){let{components:t,...a}=e;return(0,i.yg)(c,(0,n.c)({},d,a,{components:t,mdxType:"MDXLayout"}),(0,i.yg)("h2",{id:"your-first-apiato-project"},"Your First Apiato Project"),(0,i.yg)("p",null,"Before creating your first Apiato project, you should ensure that your local machine has PHP and ",(0,i.yg)("a",{parentName:"p",href:"https://getcomposer.org/"},"Composer")," installed.\nIf you are developing on macOS, PHP and Composer can be installed via ",(0,i.yg)("a",{parentName:"p",href:"https://brew.sh/"},"Homebrew"),"."),(0,i.yg)("p",null,"After you have installed PHP and Composer, you may create a new Apiato project via the Composer create-project command:"),(0,i.yg)("pre",null,(0,i.yg)("code",{parentName:"pre"},"composer create-project apiato/apiato example-app --no-scripts\n")),(0,i.yg)("h2",{id:"development-environment-setup"},"Development Environment Setup"),(0,i.yg)("p",null,"You can run ",(0,i.yg)("strong",{parentName:"p"},"Apiato")," in any environment that you can run Laravel."),(0,i.yg)("admonition",{type:"tip"},(0,i.yg)("p",{parentName:"admonition"},"Visit ",(0,i.yg)("a",{parentName:"p",href:"https://laravel.com/docs/installation#laravel-and-docker"},"Laravel Installation")," for more details.")),(0,i.yg)("h2",{id:"initial-configuration"},"Initial Configuration"),(0,i.yg)("p",null,"All the configuration files for the Laravel framework are stored in the ",(0,i.yg)("inlineCode",{parentName:"p"},"config")," folder\nand all the configuration files for the Apiato framework are stored in ",(0,i.yg)("inlineCode",{parentName:"p"},"app/Ship/Configs"),".\nEach option is documented, so feel free to look through the files and get familiar with the options available to you."),(0,i.yg)("p",null,"Apiato needs almost no additional configuration out of the box.\nYou are free to get started developing!\nHowever, you may wish to review the ",(0,i.yg)("inlineCode",{parentName:"p"},"app/Ship/Configs/apiato.php")," file and its documentation.\nIt contains several options that you may wish to change, according to your application."),(0,i.yg)("h3",{id:"environment-based-configuration"},"Environment Based Configuration"),(0,i.yg)("p",null,"Since many of Apiato configuration option values may vary\ndepending on whether your application is running on your local machine or on a production web server,\nmany important configuration values are defined using the ",(0,i.yg)("inlineCode",{parentName:"p"},".env")," file that exists at the root of your application."),(0,i.yg)("p",null,"Your ",(0,i.yg)("inlineCode",{parentName:"p"},".env")," file should not be committed to your application's source control,\nsince each developer / server using your application could require a different environment configuration.\nFurthermore, this would be a security risk in the event an intruder gains access to your source control repository,\nsince any sensitive credentials would get exposed."),(0,i.yg)("admonition",{type:"info"},(0,i.yg)("p",{parentName:"admonition"},"For more information about the ",(0,i.yg)("inlineCode",{parentName:"p"},".env")," file and environment based configuration,\ncheck out the Laravel full ",(0,i.yg)("a",{parentName:"p",href:"https://laravel.com/docs/configuration"},"configuration documentation"),".")),(0,i.yg)("h3",{id:"databases--migrations"},"Databases & Migrations"),(0,i.yg)("p",null,"Now that you have created your Apiato application, you probably want to store some data in a database.\nBy default,\nyour application's ",(0,i.yg)("inlineCode",{parentName:"p"},".env")," configuration file specifies\nthat Apiato will be interacting with a MySQL database and will access the database at ",(0,i.yg)("inlineCode",{parentName:"p"},"127.0.0.1"),".\nIf you are developing on macOS and need to install MySQL, Postgres,\nor Redis locally, you may find it convenient to utilize ",(0,i.yg)("inlineCode",{parentName:"p"},"DBngin"),"."),(0,i.yg)("p",null,"If you do not want to install MySQL or Postgres on your local machine,\nyou can always use a ",(0,i.yg)("a",{parentName:"p",href:"https://www.sqlite.org/index.html"},"SQLite")," database.\nSQLite is a small, fast, self-contained database engine.\nTo get started, create a SQLite database by creating an empty SQLite file.\nTypically, this file will exist within the database directory of your Apiato application:"),(0,i.yg)("pre",null,(0,i.yg)("code",{parentName:"pre"},"touch database/database.sqlite\n")),(0,i.yg)("p",null,"Next, update your ",(0,i.yg)("inlineCode",{parentName:"p"},".env")," configuration file to use Laravel sqlite database driver.\nYou may remove the other database configuration options:"),(0,i.yg)("pre",null,(0,i.yg)("code",{parentName:"pre",className:"language-diff"},"+ DB_CONNECTION=sqlite\n- DB_CONNECTION=mysql\n- DB_HOST=127.0.0.1\n- DB_PORT=3306\n- DB_DATABASE=homestead\n- DB_USERNAME=homestead\n- DB_PASSWORD=secret\n")),(0,i.yg)("p",null,"Once you have configured your SQLite database,\nyou may run your application's ",(0,i.yg)("a",{parentName:"p",href:"https://laravel.com/docs/migrations"},"database migrations"),",\nwhich will create your application's database tables:"),(0,i.yg)("pre",null,(0,i.yg)("code",{parentName:"pre"},"php artisan migrate\n")),(0,i.yg)("h4",{id:"default-user-roles--permissions"},"Default User, Roles & Permissions"),(0,i.yg)("p",null,"Apiato includes a default (Super Admin) user along with predefined roles and permissions.\nTo populate the database with these default values, you may execute the ",(0,i.yg)("inlineCode",{parentName:"p"},"db:seed")," command."),(0,i.yg)("pre",null,(0,i.yg)("code",{parentName:"pre"},"php artisan db:seed\n")),(0,i.yg)("h4",{id:"default-user-credentials"},"Default User Credentials:"),(0,i.yg)("ul",null,(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("span",null,"email: ",o.Q.C.G)),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("span",null,"password: ",o.Q.C.A))),(0,i.yg)("admonition",{type:"tip"},(0,i.yg)("p",{parentName:"admonition"},"You can create a new admin user using the ",(0,i.yg)("inlineCode",{parentName:"p"},"apiato:create:admin")," interactive command:"),(0,i.yg)("pre",{parentName:"admonition"},(0,i.yg)("code",{parentName:"pre"},"php artisan apiato:create:admin\n"))),(0,i.yg)("h3",{id:"authentication-configuration"},"Authentication Configuration"),(0,i.yg)("p",null,"Visit ",(0,i.yg)("a",{parentName:"p",href:"/docs/next/security/authentication"},"Authentication")," for more details."),(0,i.yg)("h3",{id:"directory-configuration"},"Directory Configuration"),(0,i.yg)("p",null,'Apiato should always be served out of the root of the "web directory" configured for your web server.\nYou should not attempt to serve a Apiato application out of a subdirectory of the "web directory".\nAttempting to do so could expose sensitive files present within your application.'),(0,i.yg)("h3",{id:"subdomain-and-api-version-prefix"},"Subdomain and API Version Prefix"),(0,i.yg)("p",null,"By default, Apiato uses ",(0,i.yg)("inlineCode",{parentName:"p"},"api")," as a subdomain for all endpoints and adds only the API version as a prefix,\nresulting in URLs like ",(0,i.yg)("inlineCode",{parentName:"p"},"api.apiato.test/v1"),".\nHowever, you can change this behavior."),(0,i.yg)("p",null,"For example, if you'd like to achieve urls like ",(0,i.yg)("inlineCode",{parentName:"p"},"apiato.test/api/"),", follow these steps:"),(0,i.yg)("ol",null,(0,i.yg)("li",{parentName:"ol"},"Open your ",(0,i.yg)("inlineCode",{parentName:"li"},".env")," file and modify the API domain by updating the ",(0,i.yg)("inlineCode",{parentName:"li"},"API_URL")," value from ",(0,i.yg)("inlineCode",{parentName:"li"},"http://api.apiato.test")," to ",(0,i.yg)("inlineCode",{parentName:"li"},"http://apiato.test")," to remove the subdomain."),(0,i.yg)("li",{parentName:"ol"},"In the ",(0,i.yg)("inlineCode",{parentName:"li"},"app/Ship/Configs/apiato.php")," configuration file:",(0,i.yg)("ul",{parentName:"li"},(0,i.yg)("li",{parentName:"ul"},"Set the ",(0,i.yg)("inlineCode",{parentName:"li"},"prefix")," to ",(0,i.yg)("inlineCode",{parentName:"li"},"api/"),"."),(0,i.yg)("li",{parentName:"ul"},"Set ",(0,i.yg)("inlineCode",{parentName:"li"},"enable_version_prefix")," to ",(0,i.yg)("inlineCode",{parentName:"li"},"false"),".")))),(0,i.yg)("h2",{id:"generating-api-documentation"},"Generating API Documentation"),(0,i.yg)("p",null,"Apiato includes a convenient ",(0,i.yg)("a",{parentName:"p",href:"/docs/next/pacakges/documentation"},"Documentation Generator")," package that utilizes ",(0,i.yg)("a",{parentName:"p",href:"https://apidocjs.com/"},"ApiDocJs")," for API documentation generation."),(0,i.yg)("p",null,"To get started, install ApiDocJs using NPM or your preferred dependency manager:"),(0,i.yg)("pre",null,(0,i.yg)("code",{parentName:"pre"},"npm install\n")),(0,i.yg)("p",null,"Next, generate the API documentation by executing the following command:"),(0,i.yg)("pre",null,(0,i.yg)("code",{parentName:"pre"},"php artisan apiato:apidoc\n")),(0,i.yg)("h2",{id:"lets-play"},"Let's Play"),(0,i.yg)("p",null,"To witness Apiato in action,\nassuming you are using the default ",(0,i.yg)("a",{parentName:"p",href:"#subdomain-and-api-version-prefix"},"Subdomain and API Version Prefix")," configuration,\nyou should be able to access the following URLs and see the following results:"),(0,i.yg)("h4",{id:"web-browser"},"Web (Browser)"),(0,i.yg)("ul",null,(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"http://apiato.test"},"http://apiato.test")," -> Apiato welcome page.")),(0,i.yg)("h4",{id:"api-http-client"},"API (HTTP Client)"),(0,i.yg)("ul",null,(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"http://api.apiato.test"},"http://api.apiato.test")," -> ",(0,i.yg)("inlineCode",{parentName:"li"},'"Welcome to Apiato"')),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"http://api.apiato.test/v1"},"http://api.apiato.test/v1")," -> ",(0,i.yg)("inlineCode",{parentName:"li"},'"Welcome to Apiato (API V1)"'))),(0,i.yg)("h2",{id:"next-steps"},"Next Steps"),(0,i.yg)("p",null,"Now that you have created your Apiato project, you may be wondering what to learn next.\nIf you're looking for a place to start, you should check out the following resources:"),(0,i.yg)("ul",null,(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"/docs/next/architecture-concepts/"},"Apiato Architecture")),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"/docs/next/getting-started/customized-laravel-components"},"Customized Laravel Components")),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"/docs/next/framework-features/"},"Framework Features")),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"/docs/next/pacakges/"},"Container Installer"))))}g.isMDXComponent=!0},25058:e=>{e.exports=JSON.parse('{"Q":{"G":{"m":"http://api.apiato.test/v1"},"C":{"G":"admin@admin.com","A":"admin"}}}')}}]); \ No newline at end of file diff --git a/assets/js/runtime~main.35c54bbc.js b/assets/js/runtime~main.54e3bf55.js similarity index 99% rename from assets/js/runtime~main.35c54bbc.js rename to assets/js/runtime~main.54e3bf55.js index 0c7073987..8f39d1522 100644 --- a/assets/js/runtime~main.35c54bbc.js +++ b/assets/js/runtime~main.54e3bf55.js @@ -1 +1 @@ -(()=>{"use strict";var e,c,a,f,b,d={},t={};function r(e){var c=t[e];if(void 0!==c)return c.exports;var a=t[e]={exports:{}};return d[e].call(a.exports,a,a.exports,r),a.exports}r.m=d,e=[],r.O=(c,a,f,b)=>{if(!a){var d=1/0;for(i=0;i=b)&&Object.keys(r.O).every((e=>r.O[e](a[o])))?a.splice(o--,1):(t=!1,b0&&e[i-1][2]>b;i--)e[i]=e[i-1];e[i]=[a,f,b]},r.n=e=>{var c=e&&e.__esModule?()=>e.default:()=>e;return r.d(c,{a:c}),c},a=Object.getPrototypeOf?e=>Object.getPrototypeOf(e):e=>e.__proto__,r.t=function(e,f){if(1&f&&(e=this(e)),8&f)return e;if("object"==typeof e&&e){if(4&f&&e.__esModule)return e;if(16&f&&"function"==typeof e.then)return e}var b=Object.create(null);r.r(b);var d={};c=c||[null,a({}),a([]),a(a)];for(var t=2&f&&e;"object"==typeof t&&!~c.indexOf(t);t=a(t))Object.getOwnPropertyNames(t).forEach((c=>d[c]=()=>e[c]));return d.default=()=>e,r.d(b,d),b},r.d=(e,c)=>{for(var a in c)r.o(c,a)&&!r.o(e,a)&&Object.defineProperty(e,a,{enumerable:!0,get:c[a]})},r.f={},r.e=e=>Promise.all(Object.keys(r.f).reduce(((c,a)=>(r.f[a](e,c),c)),[])),r.u=e=>"assets/js/"+({64:"10691446",66:"d85472ef",68:"986c3199",76:"8c9fccb5",82:"5a824d24",88:"245df310",127:"af8bcf34",192:"ad753fe5",204:"fbb5ccd8",224:"3a8a9a02",240:"31a3eb6f",276:"20bb4ef4",300:"ed111213",304:"2c8be122",308:"77c0bb11",340:"2c32570e",384:"a29806db",388:"53f60aaa",392:"abe60d8e",400:"f3323e34",464:"245b95ea",532:"1675a853",556:"ffafab28",576:"f4ed0a4d",592:"41e9fc02",608:"add102e2",640:"63cffe9f",716:"c6d7e964",726:"9dd4b0ef",760:"c21f0827",780:"b8242e5d",784:"19031211",792:"4683e51a",804:"bfdf68d4",824:"e5c09629",836:"5040bcd3",866:"a765b786",940:"db5219b9",984:"a291d650",1028:"0c2c09cf",1040:"a55de8d9",1044:"6855260d",1144:"d6d55995",1152:"4ce02702",1156:"4ee994fc",1236:"7c71f28e",1260:"38a9fada",1264:"114e21b0",1360:"2529077f",1380:"9f93909f",1424:"03d23ece",1448:"3c75101b",1504:"3919a682",1512:"fdca9218",1532:"ff4e10c4",1538:"ec989c0b",1580:"321c3473",1632:"1c74e866",1640:"69995e4b",1724:"0bfb57e8",1804:"fcdb2c3c",1808:"1958aa06",1824:"77aa4d93",1860:"10f6dc74",1912:"1ebbf8ad",1932:"023af9ff",1960:"fc7b1962",2e3:"0d59295f",2008:"2a5e16ec",2020:"31910907",2030:"8013ae06",2032:"93d36f00",2068:"53ff84c0",2134:"303f2916",2140:"360898bf",2152:"1d2ace06",2164:"e848ef61",2168:"8b4b94e0",2180:"d3ed5dd0",2208:"1db39f58",2224:"4b4e43c1",2240:"540a99bf",2252:"a8497d64",2280:"6459b84b",2288:"c8555b7b",2324:"dbdbfb09",2352:"149faf5c",2360:"b5a6ea24",2392:"99ff9a84",2492:"02e9e60d",2496:"abba3c1a",2504:"38e3e5e2",2508:"3c8cc128",2514:"f981018f",2520:"02dc5f66",2528:"0fdfb154",2540:"e08582aa",2548:"6ca79f64",2556:"92611ec4",2560:"33939c05",2620:"abd7c6e1",2632:"c4f5d8e4",2692:"99dcebb4",2704:"a193a73b",2724:"c8795c05",2728:"28b502c2",2760:"128066bb",2788:"4504fa21",2804:"66b63dfc",2813:"54071611",2844:"630dcb4d",2856:"b626b9c9",2860:"c417dca4",2900:"36ca3315",2904:"892cf132",2908:"aaf1cba5",2956:"9c612400",2968:"7b4e6d79",2988:"a10ffd78",3072:"427fd2ae",3088:"15e12a2f",3096:"1c647d6d",3104:"90c91afe",3116:"a7d0887a",3128:"9fcd2aaf",3140:"92ea068e",3164:"ace976d6",3168:"7c884429",3184:"b2c1c78c",3188:"66d590de",3240:"6e7ac859",3264:"6095db2e",3268:"e8f086b4",3284:"60321f1e",3300:"9ec0fefb",3330:"8e61a622",3336:"47a03c7f",3340:"2f4205f9",3348:"effa6628",3400:"df203c0f",3404:"57aa3e64",3408:"06abd5b6",3436:"934030ed",3440:"b7b5f722",3448:"9f7214f0",3512:"e63fc1b2",3548:"1746ec49",3564:"aa3c5b40",3638:"1c2e3411",3656:"d72ff326",3662:"40d100db",3668:"fd1ff340",3676:"dbe067dd",3732:"3dd44646",3752:"45778f4a",3764:"18ee9ead",3800:"0b3ceb4d",3808:"9ba65a7f",3872:"67ad9935",3876:"c02ab877",3878:"42656b86",3884:"82d76014",3888:"b9d99630",3936:"da8b188d",3944:"0a783a8b",3972:"2e6078dc",4006:"f2b76d46",4028:"d8325a2c",4040:"cc5c6d64",4050:"76f67042",4088:"20702474",4108:"d4124539",4128:"33f68dcb",4164:"7c142331",4184:"9d6a5804",4196:"70b24a51",4235:"f119515c",4236:"2af38141",4272:"a247f8ec",4296:"55960ee5",4300:"2f6f9645",4304:"31874089",4376:"75d21731",4412:"4d3c06b1",4416:"4a69c104",4424:"5ecea96b",4432:"ef449f35",4436:"7c87e584",4443:"92b2ca3c",4464:"491bc18c",4466:"819f8db2",4492:"3720c009",4536:"84164204",4540:"332d52b4",4624:"b4ea3a21",4664:"c3ec0a52",4700:"956e9f49",4704:"693f6ee0",4740:"374b0855",4772:"27c465e4",4776:"40185eb5",4820:"3fa6a9b5",4888:"cf3ee67c",4891:"aca4b983",4901:"87d519de",4920:"fe4c7294",4932:"9650c219",4936:"27299a3b",4944:"9cc140f3",4950:"54828236",4956:"b5a0697e",4964:"9522a145",4968:"a49f1700",4984:"e1c5dcea",4992:"c4cc7857",5016:"e8ac06ec",5108:"1626590c",5120:"05614d2f",5160:"c4023386",5203:"35891e33",5222:"b50f730b",5244:"30644fd9",5248:"b3eefa80",5308:"dae7336e",5316:"4015baac",5328:"2e3626b2",5344:"13f612ac",5420:"8882a989",5456:"826b2a47",5464:"ec13b678",5488:"4a272307",5496:"2457aad7",5544:"2f1df01f",5566:"8fce0176",5572:"7d1f259c",5596:"ef04c7c8",5606:"df6a485b",5620:"f1acbeca",5631:"eb3c6d3c",5660:"881a9bc1",5674:"b221159f",5696:"935f2afb",5728:"2ac485cd",5748:"0d75c27e",5752:"eeb62e5b",5800:"4890df88",5816:"28451e1a",5836:"c2998ab0",5882:"687b8652",5892:"30dc594d",5928:"1f987ab0",5976:"8c90118e",6e3:"c51d05bf",6011:"13d06b8c",6020:"5e76b55a",6092:"47355b93",6136:"8e0e9e2b",6176:"bacc2700",6180:"33b191bc",6262:"9cd87160",6266:"b1c5cbf2",6284:"89918c0c",6320:"23c8336c",6419:"7458314f",6428:"53df34ca",6442:"5ba01c12",6513:"de0ecdfa",6560:"1b1d605d",6568:"f187f30c",6580:"3ffc09c4",6668:"18c33990",6692:"cf7e6749",6720:"0e1a79a5",6724:"6127c255",6752:"17896441",6764:"c16bfc7e",6768:"834e3df2",6796:"8dd1624d",6808:"d055169c",6860:"2a15d269",6864:"5ea00916",6872:"db5d8c25",6876:"4d7c6870",6904:"1647ec57",6956:"28055a57",6964:"5e923e9d",6976:"144669f6",6992:"53fc899c",7040:"31053c79",7108:"450e6318",7110:"738bceb6",7120:"4e202c12",7144:"da105351",7164:"f0ea2bc1",7184:"963bb5ab",7204:"e8e0ef40",7208:"d52025df",7222:"7b0d43d2",7228:"d34bd87a",7243:"fd3f6a3d",7244:"9c985f15",7256:"4bf0522b",7272:"1b07933a",7280:"a1a6e4a2",7312:"959be4b4",7320:"f6807fb4",7332:"98999a3e",7336:"22ecef17",7348:"5ac833b0",7384:"d994236d",7412:"2b026185",7428:"653187f9",7432:"29d4a56b",7440:"0d8578a6",7456:"b65ccb97",7492:"327f2b8d",7516:"4d0c2aca",7540:"a63c68ec",7556:"bd783ed9",7604:"4d96365a",7608:"44a2c628",7688:"3b074962",7720:"8f47f31d",7736:"4610191c",7764:"d5f37c55",7776:"59ee4ecb",7792:"ddec9574",7820:"dae33245",7824:"69bce674",7844:"9bbc65ac",7868:"26084ccc",7872:"f1121274",7968:"3d9aab4f",7988:"28a91100",8008:"c7c4bc80",8040:"fa1390c3",8044:"61086f7d",8056:"9e660ab4",8112:"415f74f4",8120:"96944d2a",8140:"9944c6d1",8180:"3f06413e",8212:"6777c82a",8216:"deb44a68",8264:"14935a59",8268:"27268bf4",8276:"ecd5baba",8292:"8375e767",8368:"e5ac4d56",8376:"8ecb0387",8388:"f32194d4",8392:"4707ca8c",8403:"c3fa5730",8436:"af738211",8476:"a71c172d",8487:"13140ae3",8488:"518c31a4",8502:"62e78712",8532:"018bfed5",8564:"df8fe5f1",8592:"2ddf079f",8620:"525560b7",8632:"55ea0897",8666:"86b21c86",8756:"01255979",8800:"1b728867",8808:"ef35623d",8848:"0688ea12",8888:"7ced6537",8980:"3ce8e004",9e3:"76827885",9008:"9840276f",9020:"92ca3f12",9072:"93746dcf",9076:"94056865",9146:"f7bd22f2",9160:"1f4f2990",9188:"411cd95c",9192:"db1fb617",9220:"19bbdee1",9232:"7dbacb84",9240:"aa32d378",9248:"7768a617",9260:"9e0bb3f7",9300:"2f3ae6a8",9344:"3b382b4c",9380:"9465b6bc",9384:"fba107f3",9404:"df59c461",9424:"4047e3d8",9450:"044a7006",9480:"0aef6e2f",9496:"1abe76cc",9516:"dbbc6b2c",9540:"a8254ede",9548:"b2aa2b43",9568:"70943eb8",9572:"a8bcf301",9620:"bb0f6255",9624:"329f7802",9632:"cb5f486b",9656:"1be78505",9684:"c1bf43f6",9700:"2aaa4378",9720:"bb32ce55",9724:"58f8f5d8",9728:"bab8e2ef",9752:"a4ce67ea",9760:"1d502ec8",9764:"43ff30f2",9784:"1fa6cfaa",9890:"37833312",9936:"568e42b9",9958:"136a2cf4",9976:"bddd0f35",9988:"94009283",9998:"6aabc5ba"}[e]||e)+"."+{64:"e03d843e",66:"a2a3175d",68:"7c140542",76:"2f3d9000",82:"2a5423d2",88:"f7d4bf9d",127:"1d6a9505",148:"ce04d052",192:"fd6826d6",204:"ad77b4ec",224:"7772fd45",240:"b6868629",276:"b7de9d84",300:"cccd7d35",304:"fbf95519",308:"671143b6",340:"318f27cc",384:"498ba1c0",388:"56f0cb36",392:"35bdac05",400:"4396eb91",464:"aa166608",532:"0381da54",556:"b33d6a55",576:"0d707963",592:"2f1afd17",608:"e5e0fd43",640:"aba14ab8",716:"f5900e0e",726:"f197447c",760:"0e887fd3",780:"d0c6391c",784:"bd623f85",792:"61e31e0f",804:"8b672dfc",824:"fbdc73f1",836:"9cd0536c",866:"a4dbd854",940:"35d55f91",984:"182e8ab7",1028:"0eb1472f",1040:"f29019cb",1044:"ce14a136",1144:"32ab05a6",1152:"9920f714",1156:"0b95df45",1236:"f021ef13",1260:"9afecba6",1264:"bf69cc0e",1360:"a3662a76",1380:"27eb7eb5",1424:"58d6faa5",1448:"0791c839",1504:"230ce4cf",1512:"8a41043d",1532:"dc911aa0",1538:"3bdc0b28",1580:"6c016d82",1632:"208267e7",1640:"837e4187",1676:"b182d0d6",1724:"5792d227",1804:"5480251d",1808:"ab36ddc0",1824:"51db2f08",1848:"f5e87e7f",1860:"5a72fd3f",1912:"643ce78d",1932:"ee07d96e",1960:"1594c6f2",2e3:"699756de",2008:"3aaf1f24",2020:"9c57aed8",2030:"5e749070",2032:"9389e9bf",2068:"781a3f32",2134:"ad02c85e",2140:"942ca312",2152:"872dae6c",2164:"84cb0b3c",2168:"d285c023",2180:"3c1a886a",2208:"816a0c7a",2224:"e351b1e9",2240:"bbb57199",2252:"2abf6129",2280:"257a7b0e",2288:"26026ac3",2324:"e10dcb78",2352:"96897cd4",2360:"a30bb4e7",2392:"4ca1309f",2492:"94dc7312",2496:"bd1c8254",2504:"764c53b0",2508:"8dcc6b4b",2514:"cdb6dc50",2520:"a9450ec4",2528:"e06e4790",2540:"6c562438",2548:"237fe638",2556:"cbdd35f2",2560:"f2391da7",2592:"f79bfc25",2620:"a49e91d2",2632:"9e99648f",2692:"302f60c4",2704:"29b855cd",2724:"4c24023b",2728:"1130f732",2760:"9a294ff5",2788:"e4f7a7d3",2804:"125db56d",2813:"fdad7756",2844:"5b53eb95",2856:"1fe563d7",2860:"0540c3dc",2900:"314f4d1e",2904:"414c2fba",2908:"9899e33d",2956:"bccbe11f",2968:"0990cec0",2988:"706b078c",3072:"6a03a665",3088:"dd7086b6",3096:"935fdd63",3104:"b6b9a45d",3116:"abb8d70b",3128:"158d4028",3140:"860a029e",3164:"2f79d741",3168:"0909b306",3184:"f7aedccd",3188:"93f0783d",3240:"414ed64e",3264:"b392a7b5",3268:"b1f67458",3284:"3c85b27d",3300:"95181847",3330:"79061c76",3336:"821a5c56",3340:"cebf54b5",3348:"6be50f37",3400:"a1d2b02a",3404:"a4bdb4d0",3408:"8cf76dba",3436:"f2ea5a74",3440:"a897bd73",3448:"cb396bc4",3512:"34d0593e",3548:"d06b6769",3564:"fed6dfcf",3638:"a1e97033",3656:"f11edc6f",3662:"cb95af95",3668:"03ec2f2e",3676:"e7848cf0",3732:"53479fd9",3752:"d9ff558f",3764:"b9026d53",3800:"dfb95537",3808:"e6112df6",3872:"08497ea6",3876:"bd68bdeb",3878:"3312c963",3884:"1ba336e9",3888:"1bf95994",3936:"0951d6c3",3944:"be235f34",3972:"895e18e8",4006:"b60f28ef",4028:"6c371536",4040:"35b13b21",4050:"2fcd8697",4088:"68f7594b",4108:"d0e7efcb",4128:"425cd3d1",4164:"7076e2de",4184:"cf4b1a8b",4196:"d6a9cb1c",4235:"8aa4f1f8",4236:"039d38db",4272:"ff3c3554",4296:"f8f72c84",4300:"5abb1c55",4304:"cfdd4711",4376:"f295987b",4412:"8c636985",4416:"03c614df",4424:"49d57c0a",4432:"9fb2e433",4436:"2708aaf1",4443:"41ed0f79",4464:"8453a132",4466:"60d25c4d",4492:"057ff55e",4536:"6a531817",4540:"4e4cb182",4624:"cf2cd490",4664:"55f90633",4700:"166464d2",4704:"e1fe6f49",4740:"4950ec81",4772:"4f6c8e90",4776:"b4aa1eca",4820:"b5a6b9f9",4888:"82ae85c2",4891:"a3b3efa7",4901:"ac12d733",4920:"8beb6b75",4932:"813cbebd",4936:"93f5a6c6",4944:"88fd156f",4950:"5ae5254a",4956:"3aad476d",4964:"357238f0",4968:"6b974736",4984:"24dc9b4d",4992:"a9f4c793",5016:"5700b32f",5108:"8f5f9a80",5120:"ee6b3e70",5160:"9abfb881",5203:"37464699",5222:"b4b2f3ae",5244:"5758235c",5248:"b3c460a0",5308:"79fa30cd",5316:"6b98909d",5328:"5a9e1a76",5344:"d645b040",5420:"bc1f28ba",5456:"615fb125",5464:"47ac9494",5488:"b13f013e",5496:"3865d741",5544:"8720b9ef",5566:"366af879",5572:"3cd92a5f",5596:"1b2409bd",5606:"ddad1a20",5620:"950a6f83",5631:"59487b1d",5660:"c7c44aae",5674:"ea702f9c",5696:"f1eb8702",5728:"60b84ce1",5748:"846988bb",5752:"e08db8e5",5800:"1c683c72",5816:"ee085898",5836:"0664c43a",5882:"fd7d220b",5892:"d937092d",5928:"236cc305",5976:"10833c6f",6e3:"9973b90b",6011:"deea3b76",6020:"38044a2a",6092:"470a4b8e",6136:"72d78faa",6176:"3514dd94",6180:"7ead1419",6262:"d0f1292f",6266:"c89a7d60",6284:"5d47c466",6320:"41ddab3c",6419:"31fba5b3",6428:"f7d3ad96",6442:"fd5b9d86",6513:"ef782f41",6560:"4a6c51d5",6568:"400f22f2",6579:"5388cc08",6580:"c2453e03",6668:"4ddc7406",6692:"901f95da",6720:"8a9f16a1",6724:"06724ddb",6752:"dd61cb89",6764:"a0617972",6768:"8bb4739b",6796:"fbf17ae0",6808:"400e7bda",6860:"7a363877",6864:"102e1842",6872:"7f1d9688",6876:"7cc387d7",6904:"77f851e7",6956:"5a1f67d4",6964:"0cecdb26",6976:"226d4280",6992:"a530b4b0",7040:"d43d962b",7108:"ca99a9e4",7110:"a4138606",7120:"d6f82427",7144:"86c72098",7164:"3c8d8ede",7184:"c9ec90d4",7204:"81af1be0",7208:"44d941b2",7222:"ffe2646b",7228:"382982f4",7243:"8fd7c45b",7244:"d16a39fb",7256:"0fac1a2c",7272:"66c0a11c",7280:"b267951c",7312:"ee6f90bf",7320:"d362c5fe",7332:"7594329c",7336:"d4512163",7348:"5e0fc434",7384:"a5774bf9",7412:"7656bfed",7428:"fb13f307",7432:"5602b489",7440:"593f400d",7456:"74f458fe",7492:"542b781f",7516:"77a4fbcd",7540:"d77a4e47",7556:"7f76249c",7604:"1f0dfb0e",7608:"1d3eecd3",7688:"7aac35f5",7720:"d76fc684",7736:"7b6d5cc7",7764:"a0cbcab9",7776:"b3deb321",7792:"24db1b25",7820:"e971379b",7824:"a533f647",7844:"9ead78e2",7868:"859d0b47",7872:"65b0ccd8",7968:"563dbc3a",7988:"51232986",8008:"3d19ea33",8040:"53d02a75",8044:"976591e0",8056:"360399f4",8112:"bba7e25c",8120:"ede04743",8140:"e956a914",8180:"638ee0e5",8212:"4bbc8683",8216:"e475845a",8264:"c177acf1",8268:"ce379bdb",8276:"7b522167",8292:"e839c448",8368:"8d0ee5bd",8376:"0b77a5a6",8388:"5e3effd9",8392:"45075116",8403:"fc02a093",8436:"4a8e4069",8476:"973d031d",8487:"2371cdca",8488:"6ca68d19",8502:"08ab2486",8532:"aa370902",8564:"d38ff788",8592:"5baf8af7",8620:"58792d8f",8632:"daa2beca",8666:"fb70c63e",8756:"1b47a78f",8800:"faa9ad6a",8808:"2c2c7e65",8848:"1e279d76",8879:"e84a6a97",8888:"c0030abc",8980:"91af5075",9e3:"2c4ff459",9008:"1a5bfc05",9020:"6f0032f5",9072:"a0cbb623",9076:"85f07285",9146:"2950aab1",9160:"6785e7f1",9188:"df287e97",9192:"768ca3cc",9220:"c1f30c23",9232:"0e6c6273",9240:"6cf233c1",9248:"1c899cfc",9260:"105deba4",9300:"28a597e3",9344:"a8e564e8",9380:"d5f98963",9384:"0bbcd97d",9404:"01a5ddca",9424:"dc77bd11",9450:"a7708eac",9480:"e8ca5839",9496:"dbedb6d1",9516:"567a7ecb",9540:"338c6b28",9548:"8186f861",9568:"b09195de",9572:"d49697f3",9620:"7d49434f",9624:"b97a436a",9632:"ac178506",9656:"c22080b2",9684:"a3c2ccff",9700:"622a44d4",9720:"0d349797",9724:"d8fef2af",9728:"6cc5f542",9752:"f528e65a",9760:"d5ccd140",9764:"a314a6d6",9772:"344f2223",9784:"876c4e45",9890:"79d9dc82",9936:"e94b3327",9958:"10df8a44",9976:"763b09e8",9980:"02d2fcef",9988:"3e1bcea1",9998:"625892ff"}[e]+".js",r.miniCssF=e=>{},r.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),r.o=(e,c)=>Object.prototype.hasOwnProperty.call(e,c),f={},b="documentation:",r.l=(e,c,a,d)=>{if(f[e])f[e].push(c);else{var t,o;if(void 0!==a)for(var n=document.getElementsByTagName("script"),i=0;i{t.onerror=t.onload=null,clearTimeout(s);var b=f[e];if(delete f[e],t.parentNode&&t.parentNode.removeChild(t),b&&b.forEach((e=>e(a))),c)return c(a)},s=setTimeout(l.bind(null,void 0,{type:"timeout",target:t}),12e4);t.onerror=l.bind(null,t.onerror),t.onload=l.bind(null,t.onload),o&&document.head.appendChild(t)}},r.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},r.p="/",r.gca=function(e){return e={10691446:"64",17896441:"6752",19031211:"784",20702474:"4088",31874089:"4304",31910907:"2020",37833312:"9890",54071611:"2813",54828236:"4950",76827885:"9000",84164204:"4536",94009283:"9988",94056865:"9076",d85472ef:"66","986c3199":"68","8c9fccb5":"76","5a824d24":"82","245df310":"88",af8bcf34:"127",ad753fe5:"192",fbb5ccd8:"204","3a8a9a02":"224","31a3eb6f":"240","20bb4ef4":"276",ed111213:"300","2c8be122":"304","77c0bb11":"308","2c32570e":"340",a29806db:"384","53f60aaa":"388",abe60d8e:"392",f3323e34:"400","245b95ea":"464","1675a853":"532",ffafab28:"556",f4ed0a4d:"576","41e9fc02":"592",add102e2:"608","63cffe9f":"640",c6d7e964:"716","9dd4b0ef":"726",c21f0827:"760",b8242e5d:"780","4683e51a":"792",bfdf68d4:"804",e5c09629:"824","5040bcd3":"836",a765b786:"866",db5219b9:"940",a291d650:"984","0c2c09cf":"1028",a55de8d9:"1040","6855260d":"1044",d6d55995:"1144","4ce02702":"1152","4ee994fc":"1156","7c71f28e":"1236","38a9fada":"1260","114e21b0":"1264","2529077f":"1360","9f93909f":"1380","03d23ece":"1424","3c75101b":"1448","3919a682":"1504",fdca9218:"1512",ff4e10c4:"1532",ec989c0b:"1538","321c3473":"1580","1c74e866":"1632","69995e4b":"1640","0bfb57e8":"1724",fcdb2c3c:"1804","1958aa06":"1808","77aa4d93":"1824","10f6dc74":"1860","1ebbf8ad":"1912","023af9ff":"1932",fc7b1962:"1960","0d59295f":"2000","2a5e16ec":"2008","8013ae06":"2030","93d36f00":"2032","53ff84c0":"2068","303f2916":"2134","360898bf":"2140","1d2ace06":"2152",e848ef61:"2164","8b4b94e0":"2168",d3ed5dd0:"2180","1db39f58":"2208","4b4e43c1":"2224","540a99bf":"2240",a8497d64:"2252","6459b84b":"2280",c8555b7b:"2288",dbdbfb09:"2324","149faf5c":"2352",b5a6ea24:"2360","99ff9a84":"2392","02e9e60d":"2492",abba3c1a:"2496","38e3e5e2":"2504","3c8cc128":"2508",f981018f:"2514","02dc5f66":"2520","0fdfb154":"2528",e08582aa:"2540","6ca79f64":"2548","92611ec4":"2556","33939c05":"2560",abd7c6e1:"2620",c4f5d8e4:"2632","99dcebb4":"2692",a193a73b:"2704",c8795c05:"2724","28b502c2":"2728","128066bb":"2760","4504fa21":"2788","66b63dfc":"2804","630dcb4d":"2844",b626b9c9:"2856",c417dca4:"2860","36ca3315":"2900","892cf132":"2904",aaf1cba5:"2908","9c612400":"2956","7b4e6d79":"2968",a10ffd78:"2988","427fd2ae":"3072","15e12a2f":"3088","1c647d6d":"3096","90c91afe":"3104",a7d0887a:"3116","9fcd2aaf":"3128","92ea068e":"3140",ace976d6:"3164","7c884429":"3168",b2c1c78c:"3184","66d590de":"3188","6e7ac859":"3240","6095db2e":"3264",e8f086b4:"3268","60321f1e":"3284","9ec0fefb":"3300","8e61a622":"3330","47a03c7f":"3336","2f4205f9":"3340",effa6628:"3348",df203c0f:"3400","57aa3e64":"3404","06abd5b6":"3408","934030ed":"3436",b7b5f722:"3440","9f7214f0":"3448",e63fc1b2:"3512","1746ec49":"3548",aa3c5b40:"3564","1c2e3411":"3638",d72ff326:"3656","40d100db":"3662",fd1ff340:"3668",dbe067dd:"3676","3dd44646":"3732","45778f4a":"3752","18ee9ead":"3764","0b3ceb4d":"3800","9ba65a7f":"3808","67ad9935":"3872",c02ab877:"3876","42656b86":"3878","82d76014":"3884",b9d99630:"3888",da8b188d:"3936","0a783a8b":"3944","2e6078dc":"3972",f2b76d46:"4006",d8325a2c:"4028",cc5c6d64:"4040","76f67042":"4050",d4124539:"4108","33f68dcb":"4128","7c142331":"4164","9d6a5804":"4184","70b24a51":"4196",f119515c:"4235","2af38141":"4236",a247f8ec:"4272","55960ee5":"4296","2f6f9645":"4300","75d21731":"4376","4d3c06b1":"4412","4a69c104":"4416","5ecea96b":"4424",ef449f35:"4432","7c87e584":"4436","92b2ca3c":"4443","491bc18c":"4464","819f8db2":"4466","3720c009":"4492","332d52b4":"4540",b4ea3a21:"4624",c3ec0a52:"4664","956e9f49":"4700","693f6ee0":"4704","374b0855":"4740","27c465e4":"4772","40185eb5":"4776","3fa6a9b5":"4820",cf3ee67c:"4888",aca4b983:"4891","87d519de":"4901",fe4c7294:"4920","9650c219":"4932","27299a3b":"4936","9cc140f3":"4944",b5a0697e:"4956","9522a145":"4964",a49f1700:"4968",e1c5dcea:"4984",c4cc7857:"4992",e8ac06ec:"5016","1626590c":"5108","05614d2f":"5120",c4023386:"5160","35891e33":"5203",b50f730b:"5222","30644fd9":"5244",b3eefa80:"5248",dae7336e:"5308","4015baac":"5316","2e3626b2":"5328","13f612ac":"5344","8882a989":"5420","826b2a47":"5456",ec13b678:"5464","4a272307":"5488","2457aad7":"5496","2f1df01f":"5544","8fce0176":"5566","7d1f259c":"5572",ef04c7c8:"5596",df6a485b:"5606",f1acbeca:"5620",eb3c6d3c:"5631","881a9bc1":"5660",b221159f:"5674","935f2afb":"5696","2ac485cd":"5728","0d75c27e":"5748",eeb62e5b:"5752","4890df88":"5800","28451e1a":"5816",c2998ab0:"5836","687b8652":"5882","30dc594d":"5892","1f987ab0":"5928","8c90118e":"5976",c51d05bf:"6000","13d06b8c":"6011","5e76b55a":"6020","47355b93":"6092","8e0e9e2b":"6136",bacc2700:"6176","33b191bc":"6180","9cd87160":"6262",b1c5cbf2:"6266","89918c0c":"6284","23c8336c":"6320","7458314f":"6419","53df34ca":"6428","5ba01c12":"6442",de0ecdfa:"6513","1b1d605d":"6560",f187f30c:"6568","3ffc09c4":"6580","18c33990":"6668",cf7e6749:"6692","0e1a79a5":"6720","6127c255":"6724",c16bfc7e:"6764","834e3df2":"6768","8dd1624d":"6796",d055169c:"6808","2a15d269":"6860","5ea00916":"6864",db5d8c25:"6872","4d7c6870":"6876","1647ec57":"6904","28055a57":"6956","5e923e9d":"6964","144669f6":"6976","53fc899c":"6992","31053c79":"7040","450e6318":"7108","738bceb6":"7110","4e202c12":"7120",da105351:"7144",f0ea2bc1:"7164","963bb5ab":"7184",e8e0ef40:"7204",d52025df:"7208","7b0d43d2":"7222",d34bd87a:"7228",fd3f6a3d:"7243","9c985f15":"7244","4bf0522b":"7256","1b07933a":"7272",a1a6e4a2:"7280","959be4b4":"7312",f6807fb4:"7320","98999a3e":"7332","22ecef17":"7336","5ac833b0":"7348",d994236d:"7384","2b026185":"7412","653187f9":"7428","29d4a56b":"7432","0d8578a6":"7440",b65ccb97:"7456","327f2b8d":"7492","4d0c2aca":"7516",a63c68ec:"7540",bd783ed9:"7556","4d96365a":"7604","44a2c628":"7608","3b074962":"7688","8f47f31d":"7720","4610191c":"7736",d5f37c55:"7764","59ee4ecb":"7776",ddec9574:"7792",dae33245:"7820","69bce674":"7824","9bbc65ac":"7844","26084ccc":"7868",f1121274:"7872","3d9aab4f":"7968","28a91100":"7988",c7c4bc80:"8008",fa1390c3:"8040","61086f7d":"8044","9e660ab4":"8056","415f74f4":"8112","96944d2a":"8120","9944c6d1":"8140","3f06413e":"8180","6777c82a":"8212",deb44a68:"8216","14935a59":"8264","27268bf4":"8268",ecd5baba:"8276","8375e767":"8292",e5ac4d56:"8368","8ecb0387":"8376",f32194d4:"8388","4707ca8c":"8392",c3fa5730:"8403",af738211:"8436",a71c172d:"8476","13140ae3":"8487","518c31a4":"8488","62e78712":"8502","018bfed5":"8532",df8fe5f1:"8564","2ddf079f":"8592","525560b7":"8620","55ea0897":"8632","86b21c86":"8666","01255979":"8756","1b728867":"8800",ef35623d:"8808","0688ea12":"8848","7ced6537":"8888","3ce8e004":"8980","9840276f":"9008","92ca3f12":"9020","93746dcf":"9072",f7bd22f2:"9146","1f4f2990":"9160","411cd95c":"9188",db1fb617:"9192","19bbdee1":"9220","7dbacb84":"9232",aa32d378:"9240","7768a617":"9248","9e0bb3f7":"9260","2f3ae6a8":"9300","3b382b4c":"9344","9465b6bc":"9380",fba107f3:"9384",df59c461:"9404","4047e3d8":"9424","044a7006":"9450","0aef6e2f":"9480","1abe76cc":"9496",dbbc6b2c:"9516",a8254ede:"9540",b2aa2b43:"9548","70943eb8":"9568",a8bcf301:"9572",bb0f6255:"9620","329f7802":"9624",cb5f486b:"9632","1be78505":"9656",c1bf43f6:"9684","2aaa4378":"9700",bb32ce55:"9720","58f8f5d8":"9724",bab8e2ef:"9728",a4ce67ea:"9752","1d502ec8":"9760","43ff30f2":"9764","1fa6cfaa":"9784","568e42b9":"9936","136a2cf4":"9958",bddd0f35:"9976","6aabc5ba":"9998"}[e]||e,r.p+r.u(e)},(()=>{var e={296:0,2176:0};r.f.j=(c,a)=>{var f=r.o(e,c)?e[c]:void 0;if(0!==f)if(f)a.push(f[2]);else if(/^2(17|9)6$/.test(c))e[c]=0;else{var b=new Promise(((a,b)=>f=e[c]=[a,b]));a.push(f[2]=b);var d=r.p+r.u(c),t=new Error;r.l(d,(a=>{if(r.o(e,c)&&(0!==(f=e[c])&&(e[c]=void 0),f)){var b=a&&("load"===a.type?"missing":a.type),d=a&&a.target&&a.target.src;t.message="Loading chunk "+c+" failed.\n("+b+": "+d+")",t.name="ChunkLoadError",t.type=b,t.request=d,f[1](t)}}),"chunk-"+c,c)}},r.O.j=c=>0===e[c];var c=(c,a)=>{var f,b,d=a[0],t=a[1],o=a[2],n=0;if(d.some((c=>0!==e[c]))){for(f in t)r.o(t,f)&&(r.m[f]=t[f]);if(o)var i=o(r)}for(c&&c(a);n{"use strict";var e,c,a,f,b,d={},t={};function r(e){var c=t[e];if(void 0!==c)return c.exports;var a=t[e]={exports:{}};return d[e].call(a.exports,a,a.exports,r),a.exports}r.m=d,e=[],r.O=(c,a,f,b)=>{if(!a){var d=1/0;for(i=0;i=b)&&Object.keys(r.O).every((e=>r.O[e](a[o])))?a.splice(o--,1):(t=!1,b0&&e[i-1][2]>b;i--)e[i]=e[i-1];e[i]=[a,f,b]},r.n=e=>{var c=e&&e.__esModule?()=>e.default:()=>e;return r.d(c,{a:c}),c},a=Object.getPrototypeOf?e=>Object.getPrototypeOf(e):e=>e.__proto__,r.t=function(e,f){if(1&f&&(e=this(e)),8&f)return e;if("object"==typeof e&&e){if(4&f&&e.__esModule)return e;if(16&f&&"function"==typeof e.then)return e}var b=Object.create(null);r.r(b);var d={};c=c||[null,a({}),a([]),a(a)];for(var t=2&f&&e;"object"==typeof t&&!~c.indexOf(t);t=a(t))Object.getOwnPropertyNames(t).forEach((c=>d[c]=()=>e[c]));return d.default=()=>e,r.d(b,d),b},r.d=(e,c)=>{for(var a in c)r.o(c,a)&&!r.o(e,a)&&Object.defineProperty(e,a,{enumerable:!0,get:c[a]})},r.f={},r.e=e=>Promise.all(Object.keys(r.f).reduce(((c,a)=>(r.f[a](e,c),c)),[])),r.u=e=>"assets/js/"+({64:"10691446",66:"d85472ef",68:"986c3199",76:"8c9fccb5",82:"5a824d24",88:"245df310",127:"af8bcf34",192:"ad753fe5",204:"fbb5ccd8",224:"3a8a9a02",240:"31a3eb6f",276:"20bb4ef4",300:"ed111213",304:"2c8be122",308:"77c0bb11",340:"2c32570e",384:"a29806db",388:"53f60aaa",392:"abe60d8e",400:"f3323e34",464:"245b95ea",532:"1675a853",556:"ffafab28",576:"f4ed0a4d",592:"41e9fc02",608:"add102e2",640:"63cffe9f",716:"c6d7e964",726:"9dd4b0ef",760:"c21f0827",780:"b8242e5d",784:"19031211",792:"4683e51a",804:"bfdf68d4",824:"e5c09629",836:"5040bcd3",866:"a765b786",940:"db5219b9",984:"a291d650",1028:"0c2c09cf",1040:"a55de8d9",1044:"6855260d",1144:"d6d55995",1152:"4ce02702",1156:"4ee994fc",1236:"7c71f28e",1260:"38a9fada",1264:"114e21b0",1360:"2529077f",1380:"9f93909f",1424:"03d23ece",1448:"3c75101b",1504:"3919a682",1512:"fdca9218",1532:"ff4e10c4",1538:"ec989c0b",1580:"321c3473",1632:"1c74e866",1640:"69995e4b",1724:"0bfb57e8",1804:"fcdb2c3c",1808:"1958aa06",1824:"77aa4d93",1860:"10f6dc74",1912:"1ebbf8ad",1932:"023af9ff",1960:"fc7b1962",2e3:"0d59295f",2008:"2a5e16ec",2020:"31910907",2030:"8013ae06",2032:"93d36f00",2068:"53ff84c0",2134:"303f2916",2140:"360898bf",2152:"1d2ace06",2164:"e848ef61",2168:"8b4b94e0",2180:"d3ed5dd0",2208:"1db39f58",2224:"4b4e43c1",2240:"540a99bf",2252:"a8497d64",2280:"6459b84b",2288:"c8555b7b",2324:"dbdbfb09",2352:"149faf5c",2360:"b5a6ea24",2392:"99ff9a84",2492:"02e9e60d",2496:"abba3c1a",2504:"38e3e5e2",2508:"3c8cc128",2514:"f981018f",2520:"02dc5f66",2528:"0fdfb154",2540:"e08582aa",2548:"6ca79f64",2556:"92611ec4",2560:"33939c05",2620:"abd7c6e1",2632:"c4f5d8e4",2692:"99dcebb4",2704:"a193a73b",2724:"c8795c05",2728:"28b502c2",2760:"128066bb",2788:"4504fa21",2804:"66b63dfc",2813:"54071611",2844:"630dcb4d",2856:"b626b9c9",2860:"c417dca4",2900:"36ca3315",2904:"892cf132",2908:"aaf1cba5",2956:"9c612400",2968:"7b4e6d79",2988:"a10ffd78",3072:"427fd2ae",3088:"15e12a2f",3096:"1c647d6d",3104:"90c91afe",3116:"a7d0887a",3128:"9fcd2aaf",3140:"92ea068e",3164:"ace976d6",3168:"7c884429",3184:"b2c1c78c",3188:"66d590de",3240:"6e7ac859",3264:"6095db2e",3268:"e8f086b4",3284:"60321f1e",3300:"9ec0fefb",3330:"8e61a622",3336:"47a03c7f",3340:"2f4205f9",3348:"effa6628",3400:"df203c0f",3404:"57aa3e64",3408:"06abd5b6",3436:"934030ed",3440:"b7b5f722",3448:"9f7214f0",3512:"e63fc1b2",3548:"1746ec49",3564:"aa3c5b40",3638:"1c2e3411",3656:"d72ff326",3662:"40d100db",3668:"fd1ff340",3676:"dbe067dd",3732:"3dd44646",3752:"45778f4a",3764:"18ee9ead",3800:"0b3ceb4d",3808:"9ba65a7f",3872:"67ad9935",3876:"c02ab877",3878:"42656b86",3884:"82d76014",3888:"b9d99630",3936:"da8b188d",3944:"0a783a8b",3972:"2e6078dc",4006:"f2b76d46",4028:"d8325a2c",4040:"cc5c6d64",4050:"76f67042",4088:"20702474",4108:"d4124539",4128:"33f68dcb",4164:"7c142331",4184:"9d6a5804",4196:"70b24a51",4235:"f119515c",4236:"2af38141",4272:"a247f8ec",4296:"55960ee5",4300:"2f6f9645",4304:"31874089",4376:"75d21731",4412:"4d3c06b1",4416:"4a69c104",4424:"5ecea96b",4432:"ef449f35",4436:"7c87e584",4443:"92b2ca3c",4464:"491bc18c",4466:"819f8db2",4492:"3720c009",4536:"84164204",4540:"332d52b4",4624:"b4ea3a21",4664:"c3ec0a52",4700:"956e9f49",4704:"693f6ee0",4740:"374b0855",4772:"27c465e4",4776:"40185eb5",4820:"3fa6a9b5",4888:"cf3ee67c",4891:"aca4b983",4901:"87d519de",4920:"fe4c7294",4932:"9650c219",4936:"27299a3b",4944:"9cc140f3",4950:"54828236",4956:"b5a0697e",4964:"9522a145",4968:"a49f1700",4984:"e1c5dcea",4992:"c4cc7857",5016:"e8ac06ec",5108:"1626590c",5120:"05614d2f",5160:"c4023386",5203:"35891e33",5222:"b50f730b",5244:"30644fd9",5248:"b3eefa80",5308:"dae7336e",5316:"4015baac",5328:"2e3626b2",5344:"13f612ac",5420:"8882a989",5456:"826b2a47",5464:"ec13b678",5488:"4a272307",5496:"2457aad7",5544:"2f1df01f",5566:"8fce0176",5572:"7d1f259c",5596:"ef04c7c8",5606:"df6a485b",5620:"f1acbeca",5631:"eb3c6d3c",5660:"881a9bc1",5674:"b221159f",5696:"935f2afb",5728:"2ac485cd",5748:"0d75c27e",5752:"eeb62e5b",5800:"4890df88",5816:"28451e1a",5836:"c2998ab0",5882:"687b8652",5892:"30dc594d",5928:"1f987ab0",5976:"8c90118e",6e3:"c51d05bf",6011:"13d06b8c",6020:"5e76b55a",6092:"47355b93",6136:"8e0e9e2b",6176:"bacc2700",6180:"33b191bc",6262:"9cd87160",6266:"b1c5cbf2",6284:"89918c0c",6320:"23c8336c",6419:"7458314f",6428:"53df34ca",6442:"5ba01c12",6513:"de0ecdfa",6560:"1b1d605d",6568:"f187f30c",6580:"3ffc09c4",6668:"18c33990",6692:"cf7e6749",6720:"0e1a79a5",6724:"6127c255",6752:"17896441",6764:"c16bfc7e",6768:"834e3df2",6796:"8dd1624d",6808:"d055169c",6860:"2a15d269",6864:"5ea00916",6872:"db5d8c25",6876:"4d7c6870",6904:"1647ec57",6956:"28055a57",6964:"5e923e9d",6976:"144669f6",6992:"53fc899c",7040:"31053c79",7108:"450e6318",7110:"738bceb6",7120:"4e202c12",7144:"da105351",7164:"f0ea2bc1",7184:"963bb5ab",7204:"e8e0ef40",7208:"d52025df",7222:"7b0d43d2",7228:"d34bd87a",7243:"fd3f6a3d",7244:"9c985f15",7256:"4bf0522b",7272:"1b07933a",7280:"a1a6e4a2",7312:"959be4b4",7320:"f6807fb4",7332:"98999a3e",7336:"22ecef17",7348:"5ac833b0",7384:"d994236d",7412:"2b026185",7428:"653187f9",7432:"29d4a56b",7440:"0d8578a6",7456:"b65ccb97",7492:"327f2b8d",7516:"4d0c2aca",7540:"a63c68ec",7556:"bd783ed9",7604:"4d96365a",7608:"44a2c628",7688:"3b074962",7720:"8f47f31d",7736:"4610191c",7764:"d5f37c55",7776:"59ee4ecb",7792:"ddec9574",7820:"dae33245",7824:"69bce674",7844:"9bbc65ac",7868:"26084ccc",7872:"f1121274",7968:"3d9aab4f",7988:"28a91100",8008:"c7c4bc80",8040:"fa1390c3",8044:"61086f7d",8056:"9e660ab4",8112:"415f74f4",8120:"96944d2a",8140:"9944c6d1",8180:"3f06413e",8212:"6777c82a",8216:"deb44a68",8264:"14935a59",8268:"27268bf4",8276:"ecd5baba",8292:"8375e767",8368:"e5ac4d56",8376:"8ecb0387",8388:"f32194d4",8392:"4707ca8c",8403:"c3fa5730",8436:"af738211",8476:"a71c172d",8487:"13140ae3",8488:"518c31a4",8502:"62e78712",8532:"018bfed5",8564:"df8fe5f1",8592:"2ddf079f",8620:"525560b7",8632:"55ea0897",8666:"86b21c86",8756:"01255979",8800:"1b728867",8808:"ef35623d",8848:"0688ea12",8888:"7ced6537",8980:"3ce8e004",9e3:"76827885",9008:"9840276f",9020:"92ca3f12",9072:"93746dcf",9076:"94056865",9146:"f7bd22f2",9160:"1f4f2990",9188:"411cd95c",9192:"db1fb617",9220:"19bbdee1",9232:"7dbacb84",9240:"aa32d378",9248:"7768a617",9260:"9e0bb3f7",9300:"2f3ae6a8",9344:"3b382b4c",9380:"9465b6bc",9384:"fba107f3",9404:"df59c461",9424:"4047e3d8",9450:"044a7006",9480:"0aef6e2f",9496:"1abe76cc",9516:"dbbc6b2c",9540:"a8254ede",9548:"b2aa2b43",9568:"70943eb8",9572:"a8bcf301",9620:"bb0f6255",9624:"329f7802",9632:"cb5f486b",9656:"1be78505",9684:"c1bf43f6",9700:"2aaa4378",9720:"bb32ce55",9724:"58f8f5d8",9728:"bab8e2ef",9752:"a4ce67ea",9760:"1d502ec8",9764:"43ff30f2",9784:"1fa6cfaa",9890:"37833312",9936:"568e42b9",9958:"136a2cf4",9976:"bddd0f35",9988:"94009283",9998:"6aabc5ba"}[e]||e)+"."+{64:"e03d843e",66:"a2a3175d",68:"7c140542",76:"2f3d9000",82:"2a5423d2",88:"f7d4bf9d",127:"1d6a9505",148:"ce04d052",192:"fd6826d6",204:"ad77b4ec",224:"7772fd45",240:"b6868629",276:"b7de9d84",300:"cccd7d35",304:"fbf95519",308:"671143b6",340:"318f27cc",384:"498ba1c0",388:"56f0cb36",392:"35bdac05",400:"4396eb91",464:"aa166608",532:"0381da54",556:"b33d6a55",576:"0d707963",592:"2f1afd17",608:"e5e0fd43",640:"aba14ab8",716:"f5900e0e",726:"f197447c",760:"0e887fd3",780:"d0c6391c",784:"bd623f85",792:"61e31e0f",804:"8b672dfc",824:"fbdc73f1",836:"9cd0536c",866:"a4dbd854",940:"35d55f91",984:"182e8ab7",1028:"0eb1472f",1040:"f29019cb",1044:"ce14a136",1144:"32ab05a6",1152:"9920f714",1156:"0b95df45",1236:"f021ef13",1260:"9afecba6",1264:"bf69cc0e",1360:"a3662a76",1380:"27eb7eb5",1424:"58d6faa5",1448:"0791c839",1504:"230ce4cf",1512:"8a41043d",1532:"dc911aa0",1538:"3bdc0b28",1580:"6c016d82",1632:"208267e7",1640:"837e4187",1676:"b182d0d6",1724:"5792d227",1804:"5480251d",1808:"ab36ddc0",1824:"51db2f08",1848:"f5e87e7f",1860:"5a72fd3f",1912:"643ce78d",1932:"ee07d96e",1960:"1594c6f2",2e3:"699756de",2008:"3aaf1f24",2020:"9c57aed8",2030:"5e749070",2032:"9389e9bf",2068:"781a3f32",2134:"ad02c85e",2140:"942ca312",2152:"872dae6c",2164:"84cb0b3c",2168:"d285c023",2180:"3c1a886a",2208:"816a0c7a",2224:"e351b1e9",2240:"bbb57199",2252:"2abf6129",2280:"a79374b0",2288:"26026ac3",2324:"e10dcb78",2352:"96897cd4",2360:"a30bb4e7",2392:"4ca1309f",2492:"94dc7312",2496:"bd1c8254",2504:"764c53b0",2508:"8dcc6b4b",2514:"cdb6dc50",2520:"a9450ec4",2528:"e06e4790",2540:"6c562438",2548:"237fe638",2556:"cbdd35f2",2560:"f2391da7",2592:"f79bfc25",2620:"a49e91d2",2632:"9e99648f",2692:"302f60c4",2704:"29b855cd",2724:"4c24023b",2728:"1130f732",2760:"9a294ff5",2788:"e4f7a7d3",2804:"125db56d",2813:"fdad7756",2844:"5b53eb95",2856:"1fe563d7",2860:"0540c3dc",2900:"314f4d1e",2904:"414c2fba",2908:"9899e33d",2956:"bccbe11f",2968:"0990cec0",2988:"706b078c",3072:"6a03a665",3088:"dd7086b6",3096:"935fdd63",3104:"b6b9a45d",3116:"abb8d70b",3128:"158d4028",3140:"860a029e",3164:"2f79d741",3168:"0909b306",3184:"f7aedccd",3188:"93f0783d",3240:"414ed64e",3264:"b392a7b5",3268:"b1f67458",3284:"3c85b27d",3300:"95181847",3330:"79061c76",3336:"821a5c56",3340:"cebf54b5",3348:"6be50f37",3400:"a1d2b02a",3404:"a4bdb4d0",3408:"8cf76dba",3436:"f2ea5a74",3440:"a897bd73",3448:"cb396bc4",3512:"34d0593e",3548:"d06b6769",3564:"fed6dfcf",3638:"a1e97033",3656:"f11edc6f",3662:"cb95af95",3668:"03ec2f2e",3676:"e7848cf0",3732:"53479fd9",3752:"d9ff558f",3764:"b9026d53",3800:"dfb95537",3808:"e6112df6",3872:"08497ea6",3876:"bd68bdeb",3878:"3312c963",3884:"1ba336e9",3888:"1bf95994",3936:"0951d6c3",3944:"be235f34",3972:"895e18e8",4006:"b60f28ef",4028:"6c371536",4040:"35b13b21",4050:"2fcd8697",4088:"68f7594b",4108:"d0e7efcb",4128:"425cd3d1",4164:"7076e2de",4184:"cf4b1a8b",4196:"d6a9cb1c",4235:"8aa4f1f8",4236:"039d38db",4272:"ff3c3554",4296:"f8f72c84",4300:"5abb1c55",4304:"cfdd4711",4376:"f295987b",4412:"8c636985",4416:"03c614df",4424:"49d57c0a",4432:"9fb2e433",4436:"2708aaf1",4443:"41ed0f79",4464:"8453a132",4466:"60d25c4d",4492:"057ff55e",4536:"6a531817",4540:"4e4cb182",4624:"cf2cd490",4664:"55f90633",4700:"166464d2",4704:"e1fe6f49",4740:"4950ec81",4772:"4f6c8e90",4776:"b4aa1eca",4820:"b5a6b9f9",4888:"82ae85c2",4891:"a3b3efa7",4901:"ac12d733",4920:"8beb6b75",4932:"813cbebd",4936:"93f5a6c6",4944:"88fd156f",4950:"5ae5254a",4956:"3aad476d",4964:"357238f0",4968:"6b974736",4984:"24dc9b4d",4992:"a9f4c793",5016:"5700b32f",5108:"8f5f9a80",5120:"ee6b3e70",5160:"9abfb881",5203:"37464699",5222:"b4b2f3ae",5244:"5758235c",5248:"b3c460a0",5308:"79fa30cd",5316:"6b98909d",5328:"5a9e1a76",5344:"d645b040",5420:"bc1f28ba",5456:"615fb125",5464:"47ac9494",5488:"b13f013e",5496:"3865d741",5544:"8720b9ef",5566:"366af879",5572:"3cd92a5f",5596:"1b2409bd",5606:"ddad1a20",5620:"950a6f83",5631:"59487b1d",5660:"c7c44aae",5674:"ea702f9c",5696:"f1eb8702",5728:"60b84ce1",5748:"846988bb",5752:"e08db8e5",5800:"1c683c72",5816:"ee085898",5836:"0664c43a",5882:"fd7d220b",5892:"d937092d",5928:"236cc305",5976:"10833c6f",6e3:"9973b90b",6011:"deea3b76",6020:"38044a2a",6092:"470a4b8e",6136:"72d78faa",6176:"3514dd94",6180:"7ead1419",6262:"d0f1292f",6266:"c89a7d60",6284:"5d47c466",6320:"41ddab3c",6419:"31fba5b3",6428:"f7d3ad96",6442:"fd5b9d86",6513:"ef782f41",6560:"4a6c51d5",6568:"400f22f2",6579:"5388cc08",6580:"c2453e03",6668:"4ddc7406",6692:"901f95da",6720:"8a9f16a1",6724:"06724ddb",6752:"dd61cb89",6764:"a0617972",6768:"8bb4739b",6796:"fbf17ae0",6808:"400e7bda",6860:"7a363877",6864:"102e1842",6872:"7f1d9688",6876:"7cc387d7",6904:"77f851e7",6956:"5a1f67d4",6964:"0cecdb26",6976:"226d4280",6992:"a530b4b0",7040:"d43d962b",7108:"ca99a9e4",7110:"a4138606",7120:"d6f82427",7144:"86c72098",7164:"3c8d8ede",7184:"c9ec90d4",7204:"81af1be0",7208:"44d941b2",7222:"ffe2646b",7228:"382982f4",7243:"8fd7c45b",7244:"d16a39fb",7256:"0fac1a2c",7272:"66c0a11c",7280:"b267951c",7312:"ee6f90bf",7320:"d362c5fe",7332:"7594329c",7336:"d4512163",7348:"5e0fc434",7384:"a5774bf9",7412:"7656bfed",7428:"fb13f307",7432:"5602b489",7440:"593f400d",7456:"74f458fe",7492:"542b781f",7516:"77a4fbcd",7540:"d77a4e47",7556:"7f76249c",7604:"1f0dfb0e",7608:"1d3eecd3",7688:"7aac35f5",7720:"d76fc684",7736:"7b6d5cc7",7764:"a0cbcab9",7776:"b3deb321",7792:"24db1b25",7820:"e971379b",7824:"a533f647",7844:"9ead78e2",7868:"859d0b47",7872:"65b0ccd8",7968:"563dbc3a",7988:"51232986",8008:"3d19ea33",8040:"53d02a75",8044:"976591e0",8056:"360399f4",8112:"bba7e25c",8120:"ede04743",8140:"e956a914",8180:"638ee0e5",8212:"4bbc8683",8216:"e475845a",8264:"c177acf1",8268:"ce379bdb",8276:"7b522167",8292:"e839c448",8368:"8d0ee5bd",8376:"0b77a5a6",8388:"5e3effd9",8392:"45075116",8403:"fc02a093",8436:"4a8e4069",8476:"973d031d",8487:"2371cdca",8488:"6ca68d19",8502:"08ab2486",8532:"aa370902",8564:"d38ff788",8592:"5baf8af7",8620:"58792d8f",8632:"daa2beca",8666:"fb70c63e",8756:"1b47a78f",8800:"faa9ad6a",8808:"2c2c7e65",8848:"1e279d76",8879:"e84a6a97",8888:"c0030abc",8980:"91af5075",9e3:"2c4ff459",9008:"1a5bfc05",9020:"6f0032f5",9072:"a0cbb623",9076:"85f07285",9146:"2950aab1",9160:"8bcc2ebe",9188:"df287e97",9192:"768ca3cc",9220:"c1f30c23",9232:"0e6c6273",9240:"6cf233c1",9248:"1c899cfc",9260:"105deba4",9300:"28a597e3",9344:"a8e564e8",9380:"d5f98963",9384:"0bbcd97d",9404:"01a5ddca",9424:"dc77bd11",9450:"a7708eac",9480:"e8ca5839",9496:"dbedb6d1",9516:"567a7ecb",9540:"338c6b28",9548:"8186f861",9568:"b09195de",9572:"d49697f3",9620:"7d49434f",9624:"b97a436a",9632:"ac178506",9656:"c22080b2",9684:"a3c2ccff",9700:"622a44d4",9720:"0d349797",9724:"d8fef2af",9728:"6cc5f542",9752:"f528e65a",9760:"d5ccd140",9764:"a314a6d6",9772:"344f2223",9784:"876c4e45",9890:"79d9dc82",9936:"e94b3327",9958:"10df8a44",9976:"763b09e8",9980:"02d2fcef",9988:"3e1bcea1",9998:"625892ff"}[e]+".js",r.miniCssF=e=>{},r.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),r.o=(e,c)=>Object.prototype.hasOwnProperty.call(e,c),f={},b="documentation:",r.l=(e,c,a,d)=>{if(f[e])f[e].push(c);else{var t,o;if(void 0!==a)for(var n=document.getElementsByTagName("script"),i=0;i{t.onerror=t.onload=null,clearTimeout(s);var b=f[e];if(delete f[e],t.parentNode&&t.parentNode.removeChild(t),b&&b.forEach((e=>e(a))),c)return c(a)},s=setTimeout(l.bind(null,void 0,{type:"timeout",target:t}),12e4);t.onerror=l.bind(null,t.onerror),t.onload=l.bind(null,t.onload),o&&document.head.appendChild(t)}},r.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},r.p="/",r.gca=function(e){return e={10691446:"64",17896441:"6752",19031211:"784",20702474:"4088",31874089:"4304",31910907:"2020",37833312:"9890",54071611:"2813",54828236:"4950",76827885:"9000",84164204:"4536",94009283:"9988",94056865:"9076",d85472ef:"66","986c3199":"68","8c9fccb5":"76","5a824d24":"82","245df310":"88",af8bcf34:"127",ad753fe5:"192",fbb5ccd8:"204","3a8a9a02":"224","31a3eb6f":"240","20bb4ef4":"276",ed111213:"300","2c8be122":"304","77c0bb11":"308","2c32570e":"340",a29806db:"384","53f60aaa":"388",abe60d8e:"392",f3323e34:"400","245b95ea":"464","1675a853":"532",ffafab28:"556",f4ed0a4d:"576","41e9fc02":"592",add102e2:"608","63cffe9f":"640",c6d7e964:"716","9dd4b0ef":"726",c21f0827:"760",b8242e5d:"780","4683e51a":"792",bfdf68d4:"804",e5c09629:"824","5040bcd3":"836",a765b786:"866",db5219b9:"940",a291d650:"984","0c2c09cf":"1028",a55de8d9:"1040","6855260d":"1044",d6d55995:"1144","4ce02702":"1152","4ee994fc":"1156","7c71f28e":"1236","38a9fada":"1260","114e21b0":"1264","2529077f":"1360","9f93909f":"1380","03d23ece":"1424","3c75101b":"1448","3919a682":"1504",fdca9218:"1512",ff4e10c4:"1532",ec989c0b:"1538","321c3473":"1580","1c74e866":"1632","69995e4b":"1640","0bfb57e8":"1724",fcdb2c3c:"1804","1958aa06":"1808","77aa4d93":"1824","10f6dc74":"1860","1ebbf8ad":"1912","023af9ff":"1932",fc7b1962:"1960","0d59295f":"2000","2a5e16ec":"2008","8013ae06":"2030","93d36f00":"2032","53ff84c0":"2068","303f2916":"2134","360898bf":"2140","1d2ace06":"2152",e848ef61:"2164","8b4b94e0":"2168",d3ed5dd0:"2180","1db39f58":"2208","4b4e43c1":"2224","540a99bf":"2240",a8497d64:"2252","6459b84b":"2280",c8555b7b:"2288",dbdbfb09:"2324","149faf5c":"2352",b5a6ea24:"2360","99ff9a84":"2392","02e9e60d":"2492",abba3c1a:"2496","38e3e5e2":"2504","3c8cc128":"2508",f981018f:"2514","02dc5f66":"2520","0fdfb154":"2528",e08582aa:"2540","6ca79f64":"2548","92611ec4":"2556","33939c05":"2560",abd7c6e1:"2620",c4f5d8e4:"2632","99dcebb4":"2692",a193a73b:"2704",c8795c05:"2724","28b502c2":"2728","128066bb":"2760","4504fa21":"2788","66b63dfc":"2804","630dcb4d":"2844",b626b9c9:"2856",c417dca4:"2860","36ca3315":"2900","892cf132":"2904",aaf1cba5:"2908","9c612400":"2956","7b4e6d79":"2968",a10ffd78:"2988","427fd2ae":"3072","15e12a2f":"3088","1c647d6d":"3096","90c91afe":"3104",a7d0887a:"3116","9fcd2aaf":"3128","92ea068e":"3140",ace976d6:"3164","7c884429":"3168",b2c1c78c:"3184","66d590de":"3188","6e7ac859":"3240","6095db2e":"3264",e8f086b4:"3268","60321f1e":"3284","9ec0fefb":"3300","8e61a622":"3330","47a03c7f":"3336","2f4205f9":"3340",effa6628:"3348",df203c0f:"3400","57aa3e64":"3404","06abd5b6":"3408","934030ed":"3436",b7b5f722:"3440","9f7214f0":"3448",e63fc1b2:"3512","1746ec49":"3548",aa3c5b40:"3564","1c2e3411":"3638",d72ff326:"3656","40d100db":"3662",fd1ff340:"3668",dbe067dd:"3676","3dd44646":"3732","45778f4a":"3752","18ee9ead":"3764","0b3ceb4d":"3800","9ba65a7f":"3808","67ad9935":"3872",c02ab877:"3876","42656b86":"3878","82d76014":"3884",b9d99630:"3888",da8b188d:"3936","0a783a8b":"3944","2e6078dc":"3972",f2b76d46:"4006",d8325a2c:"4028",cc5c6d64:"4040","76f67042":"4050",d4124539:"4108","33f68dcb":"4128","7c142331":"4164","9d6a5804":"4184","70b24a51":"4196",f119515c:"4235","2af38141":"4236",a247f8ec:"4272","55960ee5":"4296","2f6f9645":"4300","75d21731":"4376","4d3c06b1":"4412","4a69c104":"4416","5ecea96b":"4424",ef449f35:"4432","7c87e584":"4436","92b2ca3c":"4443","491bc18c":"4464","819f8db2":"4466","3720c009":"4492","332d52b4":"4540",b4ea3a21:"4624",c3ec0a52:"4664","956e9f49":"4700","693f6ee0":"4704","374b0855":"4740","27c465e4":"4772","40185eb5":"4776","3fa6a9b5":"4820",cf3ee67c:"4888",aca4b983:"4891","87d519de":"4901",fe4c7294:"4920","9650c219":"4932","27299a3b":"4936","9cc140f3":"4944",b5a0697e:"4956","9522a145":"4964",a49f1700:"4968",e1c5dcea:"4984",c4cc7857:"4992",e8ac06ec:"5016","1626590c":"5108","05614d2f":"5120",c4023386:"5160","35891e33":"5203",b50f730b:"5222","30644fd9":"5244",b3eefa80:"5248",dae7336e:"5308","4015baac":"5316","2e3626b2":"5328","13f612ac":"5344","8882a989":"5420","826b2a47":"5456",ec13b678:"5464","4a272307":"5488","2457aad7":"5496","2f1df01f":"5544","8fce0176":"5566","7d1f259c":"5572",ef04c7c8:"5596",df6a485b:"5606",f1acbeca:"5620",eb3c6d3c:"5631","881a9bc1":"5660",b221159f:"5674","935f2afb":"5696","2ac485cd":"5728","0d75c27e":"5748",eeb62e5b:"5752","4890df88":"5800","28451e1a":"5816",c2998ab0:"5836","687b8652":"5882","30dc594d":"5892","1f987ab0":"5928","8c90118e":"5976",c51d05bf:"6000","13d06b8c":"6011","5e76b55a":"6020","47355b93":"6092","8e0e9e2b":"6136",bacc2700:"6176","33b191bc":"6180","9cd87160":"6262",b1c5cbf2:"6266","89918c0c":"6284","23c8336c":"6320","7458314f":"6419","53df34ca":"6428","5ba01c12":"6442",de0ecdfa:"6513","1b1d605d":"6560",f187f30c:"6568","3ffc09c4":"6580","18c33990":"6668",cf7e6749:"6692","0e1a79a5":"6720","6127c255":"6724",c16bfc7e:"6764","834e3df2":"6768","8dd1624d":"6796",d055169c:"6808","2a15d269":"6860","5ea00916":"6864",db5d8c25:"6872","4d7c6870":"6876","1647ec57":"6904","28055a57":"6956","5e923e9d":"6964","144669f6":"6976","53fc899c":"6992","31053c79":"7040","450e6318":"7108","738bceb6":"7110","4e202c12":"7120",da105351:"7144",f0ea2bc1:"7164","963bb5ab":"7184",e8e0ef40:"7204",d52025df:"7208","7b0d43d2":"7222",d34bd87a:"7228",fd3f6a3d:"7243","9c985f15":"7244","4bf0522b":"7256","1b07933a":"7272",a1a6e4a2:"7280","959be4b4":"7312",f6807fb4:"7320","98999a3e":"7332","22ecef17":"7336","5ac833b0":"7348",d994236d:"7384","2b026185":"7412","653187f9":"7428","29d4a56b":"7432","0d8578a6":"7440",b65ccb97:"7456","327f2b8d":"7492","4d0c2aca":"7516",a63c68ec:"7540",bd783ed9:"7556","4d96365a":"7604","44a2c628":"7608","3b074962":"7688","8f47f31d":"7720","4610191c":"7736",d5f37c55:"7764","59ee4ecb":"7776",ddec9574:"7792",dae33245:"7820","69bce674":"7824","9bbc65ac":"7844","26084ccc":"7868",f1121274:"7872","3d9aab4f":"7968","28a91100":"7988",c7c4bc80:"8008",fa1390c3:"8040","61086f7d":"8044","9e660ab4":"8056","415f74f4":"8112","96944d2a":"8120","9944c6d1":"8140","3f06413e":"8180","6777c82a":"8212",deb44a68:"8216","14935a59":"8264","27268bf4":"8268",ecd5baba:"8276","8375e767":"8292",e5ac4d56:"8368","8ecb0387":"8376",f32194d4:"8388","4707ca8c":"8392",c3fa5730:"8403",af738211:"8436",a71c172d:"8476","13140ae3":"8487","518c31a4":"8488","62e78712":"8502","018bfed5":"8532",df8fe5f1:"8564","2ddf079f":"8592","525560b7":"8620","55ea0897":"8632","86b21c86":"8666","01255979":"8756","1b728867":"8800",ef35623d:"8808","0688ea12":"8848","7ced6537":"8888","3ce8e004":"8980","9840276f":"9008","92ca3f12":"9020","93746dcf":"9072",f7bd22f2:"9146","1f4f2990":"9160","411cd95c":"9188",db1fb617:"9192","19bbdee1":"9220","7dbacb84":"9232",aa32d378:"9240","7768a617":"9248","9e0bb3f7":"9260","2f3ae6a8":"9300","3b382b4c":"9344","9465b6bc":"9380",fba107f3:"9384",df59c461:"9404","4047e3d8":"9424","044a7006":"9450","0aef6e2f":"9480","1abe76cc":"9496",dbbc6b2c:"9516",a8254ede:"9540",b2aa2b43:"9548","70943eb8":"9568",a8bcf301:"9572",bb0f6255:"9620","329f7802":"9624",cb5f486b:"9632","1be78505":"9656",c1bf43f6:"9684","2aaa4378":"9700",bb32ce55:"9720","58f8f5d8":"9724",bab8e2ef:"9728",a4ce67ea:"9752","1d502ec8":"9760","43ff30f2":"9764","1fa6cfaa":"9784","568e42b9":"9936","136a2cf4":"9958",bddd0f35:"9976","6aabc5ba":"9998"}[e]||e,r.p+r.u(e)},(()=>{var e={296:0,2176:0};r.f.j=(c,a)=>{var f=r.o(e,c)?e[c]:void 0;if(0!==f)if(f)a.push(f[2]);else if(/^2(17|9)6$/.test(c))e[c]=0;else{var b=new Promise(((a,b)=>f=e[c]=[a,b]));a.push(f[2]=b);var d=r.p+r.u(c),t=new Error;r.l(d,(a=>{if(r.o(e,c)&&(0!==(f=e[c])&&(e[c]=void 0),f)){var b=a&&("load"===a.type?"missing":a.type),d=a&&a.target&&a.target.src;t.message="Loading chunk "+c+" failed.\n("+b+": "+d+")",t.name="ChunkLoadError",t.type=b,t.request=d,f[1](t)}}),"chunk-"+c,c)}},r.O.j=c=>0===e[c];var c=(c,a)=>{var f,b,d=a[0],t=a[1],o=a[2],n=0;if(d.some((c=>0!==e[c]))){for(f in t)r.o(t,f)&&(r.m[f]=t[f]);if(o)var i=o(r)}for(c&&c(a);n Debugger | Apiato - + @@ -12,7 +12,7 @@
Version: 10.x

Debugger

Apiato provides a simple and easy way to monitor and log all the HTTP requests coming to your application.

The request monitor can be very useful when testing and debugging your frontend Apps which consume your API. Especially when the frontend apps (Mobile, Web,...) are built by other developers who are far from you.

The requests monitoring is provided via theRequestsMonitorMiddleware middleware.

Installation

composer require apiato/debugger-container
tip

This container is installed by default with an Apiato fresh installation.

Enable Requests Logging

Set REQUESTS_DEBUG and APP_DEBUG to true in .env file .

Usage

Log will be written to storage/logs/debugger.log

Debugger Customization

Instructions

This container works out of the box perfectly but if you want to change its configs or modify the codes you MUST follow these steps:

1- Copy the container from Vendor to AppSection (or any of your custom sections) of your project
2- Fix the namespaces
3- Remove apiato/debugger-container dependency from project root composer.json

Change the Default Log File

By default, everything is logged in the debugger.log file, to change the default file go to Debugger/Configs/debugger.php config file and set the file name:

/*

|--------------------------------------------------------------------------
| Log File
|--------------------------------------------------------------------------
|
| What to name the log file in the `storage/log` path.
|
*/

'log_file' => 'debugger.log',

Run in Testing Environments

Request monitoring will not run in testing environments, to enable it you need to manually edit the Middleware.

- + \ No newline at end of file diff --git a/docs/10.x/additional-features/apiato-containers/documentation/index.html b/docs/10.x/additional-features/apiato-containers/documentation/index.html index 8023f3b4d..5ed70f290 100644 --- a/docs/10.x/additional-features/apiato-containers/documentation/index.html +++ b/docs/10.x/additional-features/apiato-containers/documentation/index.html @@ -4,7 +4,7 @@ Documentation | Apiato - + @@ -17,7 +17,7 @@ 3- Remove apiato/documentation-generator-container dependency from project root composer.json
4- Update section_name & html_files in container configs
5- Update apidoc.json files in ApiDocJs/private & public folders and fix the filename

{
"header": {
"filename": "Containers/NEW_SECTION_NAME/Documentation/UI/WEB/Views/documentation/header.md"
}
}

Edit Default Generated Values in Templates

Apiato by defaults generates 2 API documentations, each one has its own apidoc.json file. Both can be modified from the Documentation Containers in Containers/Vendor/Documentation/ApiDocJs/

Change the Documentations URL's

Edit the config file of the Documentation Container Containers/Vendor/Documentation/Configs/vendor-documentation.php

Edit the Documentation Header

The header is usually the Overview of your API. It contains Info about authenticating users, making requests, responses, potential errors, rate limiting, pagination, query parameters and anything you want.

All this information is written in app/Containers/Vendor/Documentation/ApiDocJs/shared/header.template.md file, and the same file is used as header for both private and public documentations.

To edit the content just open the markdown file in any markdown editor and edit it.

You will notice some variables like {{rate-limit}} and {{token-expires}}. Those are replaced when running apiato:apidoc with real values from your application configuration files.

Feel free to extend them to include more info about your API from the app/Containers/Vendor/Documentation/Tasks/RenderTemplatesTask.php class.

Localization for Documentation Header

Default, the documentation title is in English en localization.

See which locales are supported by going in app/Containers/Vendor/Documentation/ApiDocJs/shared/

There will be some header.template.{locale}.md files in the folder.

You can change the language by adding APIDOC_LOCALE=ru to the .env file.

If you didn't find a file with your locale, you can create it. You need to modify its source code and create new file like header.template.cn.md

- + \ No newline at end of file diff --git a/docs/10.x/additional-features/apiato-containers/localization/index.html b/docs/10.x/additional-features/apiato-containers/localization/index.html index f5e5845ec..9d6d9e220 100644 --- a/docs/10.x/additional-features/apiato-containers/localization/index.html +++ b/docs/10.x/additional-features/apiato-containers/localization/index.html @@ -4,7 +4,7 @@ Localization | Apiato - + @@ -38,7 +38,7 @@ language in this specific language (e.g., locale_name => Deutsch). Furthermore, the language name is outputted in the applications default name (e.g., configured in app.locale). This would result in default_name => German.

The same applies to the regions that are defined (e.g., de-DE). Consequently, this results in locale_name => Deutschland and default_name = Germany.

Tests

To change the default language in your tests requests. You can set the env language in the phpunit.xml file.

- + \ No newline at end of file diff --git a/docs/10.x/additional-features/apiato-containers/overview/index.html b/docs/10.x/additional-features/apiato-containers/overview/index.html index 057bb1d22..2be27fc86 100644 --- a/docs/10.x/additional-features/apiato-containers/overview/index.html +++ b/docs/10.x/additional-features/apiato-containers/overview/index.html @@ -4,14 +4,14 @@ Overview | Apiato - +
Version: 10.x

Overview

Apiato ships with a few pre-defined and pre-configured containers. Some of these containers (e.g. Documentation & Debugger) are installed by default with a fresh Apiato project.

- + \ No newline at end of file diff --git a/docs/10.x/additional-features/apiato-containers/payments/index.html b/docs/10.x/additional-features/apiato-containers/payments/index.html index 174588a70..2fe738b2e 100644 --- a/docs/10.x/additional-features/apiato-containers/payments/index.html +++ b/docs/10.x/additional-features/apiato-containers/payments/index.html @@ -4,7 +4,7 @@ Payments | Apiato - + @@ -38,7 +38,7 @@ need to create your own ChargeWithFooTask. This class, however, needs to implement the PaymentChargerInterface distributed via the Payment container. This interface, in turn, requires you to implement the charge() method.

This method needs to connect to the FooService, create the payment and return a PaymentTransaction model.

Finally, you need to register the new service. This can be done in the Payment\Configs\vendor-payment.php file. For the vendor-payment.gateways key, add the new entry for your Foo Payment Gateway. This may look like this:

    // ...
'foo' => [
'container' => 'Foo',
'charge_task' => \App\Containers\Foo\Tasks\ChargeWithFooTask::class,
],
// ...

Basically, this entry points to the charger_task that handles, how to charge a User with the specific Payment Gateway.

That's all!

Mocking the real payment call for Testing

// mock the ChargeWithStripeService external API call
$this->mockIt(ChargeWithStripeService::class)->shouldReceive('charge')->andReturn([
'payment_method' => 'stripe',
'description' => $payId
]);

// mock the ChargeWithPaypalService external API call
$this->mockIt(ChargeWithPaypalService::class)->shouldReceive('charge')->andReturn([
'payment_method' => 'paypal',
'description' => $payId
]);

Checkout the Tests Helpers page for more information about Testing.

- + \ No newline at end of file diff --git a/docs/10.x/additional-features/apiato-containers/settings/index.html b/docs/10.x/additional-features/apiato-containers/settings/index.html index 20f3ef431..8269a4f9a 100644 --- a/docs/10.x/additional-features/apiato-containers/settings/index.html +++ b/docs/10.x/additional-features/apiato-containers/settings/index.html @@ -4,7 +4,7 @@ Settings | Apiato - + @@ -12,7 +12,7 @@
Version: 10.x

Settings

Installation

composer require apiato/settings-container

Now run php artisan migrate

Seed the default settings

Instructions

This container works out of the box perfectly but if you want to change its configs or modify the codes you MUST follow these steps:

1- Copy the container from Vendor to AppSection (or any of your custom sections) of your project
2- Fix the namespaces
3- Remove apiato/settings-container dependency from project root composer.json

Seed default settings in app/Containers/YourSection/Settings/Database/Seeders/DefaultSystemSettingsSeeder.php

Read settings

$value = $this->findSettingsByKeyTask->run('whateverSettingsName');

You can search for settings by Key as in the example above, or create a class for each setting as follows:

$value = $this->findWhateverSettingsTask->run();
- + \ No newline at end of file diff --git a/docs/10.x/additional-features/apiato-containers/social-authentication/index.html b/docs/10.x/additional-features/apiato-containers/social-authentication/index.html index 878b19c79..7848b2e3e 100644 --- a/docs/10.x/additional-features/apiato-containers/social-authentication/index.html +++ b/docs/10.x/additional-features/apiato-containers/social-authentication/index.html @@ -4,7 +4,7 @@ Social Authentication | Apiato - + @@ -21,7 +21,7 @@ 2- Fix the namespaces
3- Remove apiato/social-auth-container dependency from project root composer.json

1) Pick an Auth Provider from the supported providers by Socialite.
2) Go to app/Containers/YourSection/Socialauth/Tasks/FindUserSocialProfileTask.php and support your provider.

- + \ No newline at end of file diff --git a/docs/10.x/additional-features/community-containers/overview/index.html b/docs/10.x/additional-features/community-containers/overview/index.html index f67a4a203..7d464c8a2 100644 --- a/docs/10.x/additional-features/community-containers/overview/index.html +++ b/docs/10.x/additional-features/community-containers/overview/index.html @@ -4,7 +4,7 @@ Overview | Apiato - + @@ -13,7 +13,7 @@ features in form of a respective container using Container Installer. Although these containers may work perfectly out of the box, they only serve as some kind of "blueprint" in order to get you kickstart your own application. These containers may not contain "production-ready code". Please revise them carefully.

note

These containers are developed by Apiato community and provided as is.

Feel free to add your containers to this list.

How to contribute

  1. Add a good documentation to your container.
  2. Make a PR and add your repository

Community Containers

NameDescriptionLink
ActivityLogLog Activities of Users and ModelsGitHub
NoteA Container handling Notes (e.g., ToDo Lists) for Eloquent Models.GitHub
MFAA Container to manage 2 Factor Authentication works with any Authenticator app.GitHub
SanctumImplementation of Laravel Sanctum in Apiato.GitHub
- + \ No newline at end of file diff --git a/docs/10.x/contribution-guide/index.html b/docs/10.x/contribution-guide/index.html index efd546f68..b6883ac44 100644 --- a/docs/10.x/contribution-guide/index.html +++ b/docs/10.x/contribution-guide/index.html @@ -4,7 +4,7 @@ Contribution Guide | Apiato - + @@ -42,7 +42,7 @@ 3 - Make sure you write a complete Changelog, in the release description. 4 - Change the default branch on GitHub to that new branch. 5 - If you updated the documentation, and you should! then visit the documentation repository and merge the PR into master.

- + \ No newline at end of file diff --git a/docs/10.x/core-features/api-versioning/index.html b/docs/10.x/core-features/api-versioning/index.html index b6a481ddd..4cf44b564 100644 --- a/docs/10.x/core-features/api-versioning/index.html +++ b/docs/10.x/core-features/api-versioning/index.html @@ -4,13 +4,13 @@ API Versioning | Apiato - +
Version: 10.x

API Versioning

Since Laravel does not support API versioning, Apiato provide a very easy way to implement versioning for your API.

How it works

Create:

When creating a new API endpoint, specify the version number in the route file name following this naming format {endpoint-name}.{version-number}.{documentation-name}.php.

Example:

  • MakeOrder.v1.public.php
  • MakeOrder.v2.public.php
  • ListOrders.v1.private.php

Use:

Automatically the endpoint inside that route file will be accessible by adding the version number to the URL.

Example:

  • http://api.apiato.test/v1/register
  • http://api.apiato.test/v1/orders
  • http://api.apiato.test/v2/stores/123

Version the API in header instead of URL

First remove the URL version prefix:

  1. Edit app/Ship/Configs/apiato.php, set prefix to 'enable_version_prefix' => 'false',.
  2. Implement the Header versioning anyway you prefer. (this is not implemented in Apiato yet. Consider a contribution).
- + \ No newline at end of file diff --git a/docs/10.x/core-features/authentication/index.html b/docs/10.x/core-features/authentication/index.html index 4bf30de83..66e0250e3 100644 --- a/docs/10.x/core-features/authentication/index.html +++ b/docs/10.x/core-features/authentication/index.html @@ -4,7 +4,7 @@ Authentication | Apiato - + @@ -58,7 +58,7 @@ It will email you a link and when you make a request to that link it will call the /password-reset endpoint.

Note: For security reason, make sure the reset password URL is set in app/Containers/AppSection/User/Configs/appSection-user.php and given to the client App to be sent as parameter when calling the /password-forgot.

Note: You must set up the email to get this function to work, however for testing purposes set the MAIL_DRIVER=log in your .env file in order to the see the email content in the log file storage/logs/laravel.log.

Social Authentication

For Social Authentication visit the Social Authentication page.

- + \ No newline at end of file diff --git a/docs/10.x/core-features/authorization/index.html b/docs/10.x/core-features/authorization/index.html index 57dfd8723..0cfc6e11f 100644 --- a/docs/10.x/core-features/authorization/index.html +++ b/docs/10.x/core-features/authorization/index.html @@ -4,13 +4,13 @@ Authorization | Apiato - +
Version: 10.x

Authorization

Apiato provides a Role-Based Access Control (RBAC) through its Authorization Container.

Behind the scenes apiato is using the Laravel's authorization functionality that was introduced in version 5.1.11 with the helper package laravel-permission. So you can always refer to the correspond documentation for more information.

How it works

Authorization in apiato is very simple and easy.

1) Create some Roles and permissions. By default, an admin role and some permissions are provided by Apiato. You can find the code in app/Containers/AppSection/Authorization/Data/Seeders/* directory.

2) Attach some permissions to the roles.

3) Now start creating users (or use existing users), to assign them to the new created Roles.

4) Finally, you need to protect your endpoints by Permissions (or/and Roles). The right place to do that is the Requests class.

Example protecting the (delete user) endpoint with delete-users permission:

class DeleteUserRequest extends Request
{
protected array $access = [
'permissions' => 'delete-users',
'roles' => '',
];

public function authorize(): bool
{
return $this->check([
'hasAccess',
]);
}
}

For detailed explanation of this example, please visit the Requests Page.

Responses

Authorization failed JSON response:

{
"message": "This action is unauthorized."
}

Assign Roles & Permission to the Testing User

You will need to set $access property in your test class, check out the Tests Helpers page for more details.

Seeding some users (Admins)

By default, Apiato comes with a Super Admin.

This Super Admin Credentials are:

This Admin seeded by app/Containers/Authorization/Data/Seeders/AuthorizationDefaultUsersSeeder_3.php.

The Default Super User, has a default role admin.

The admin default role has no permissions given to it.

To give permissions to the admin role (or any other role), you can use the dedicated endpoints (from your custom Admin Interface) or use this command php artisan apiato:permissions:toRole admin to give it all the permissions in the system.

Checkout each container Seeders directory app/Containers/AppSection/{container-name}/Data/Seeders/, to edit the default Users, Roles and Permissions.

Roles & Permissions guards

By default, Apiato uses a single guard called web for all it's roles and permissions, you can add/edit this behavior and support multiple guards at any time. Refer to the laravel-permission package for more details.

- + \ No newline at end of file diff --git a/docs/10.x/core-features/code-generator/index.html b/docs/10.x/core-features/code-generator/index.html index a50e0347b..d077a9d8a 100644 --- a/docs/10.x/core-features/code-generator/index.html +++ b/docs/10.x/core-features/code-generator/index.html @@ -4,7 +4,7 @@ Code Generator | Apiato - + @@ -17,7 +17,7 @@ the file and the folder structure needs to be the same as in vendor/apiato/core/Generator/Stubs.

Say, if you like to change the action -> create.stub, simply copy the file to app/Ship/Generators/CustomStubs/actions/create.stub and start adapting it to your needs.

If you run the respective command (e.g., in this case php artisan apiato:generate:action) and choose Create type this would read your specific create.stub file instead of the pre-defined one!

Contributing

If you would like to add your own generators, please check out the Contribution Guide.

- + \ No newline at end of file diff --git a/docs/10.x/core-features/data-caching/index.html b/docs/10.x/core-features/data-caching/index.html index 010aa1b71..195b47cf4 100644 --- a/docs/10.x/core-features/data-caching/index.html +++ b/docs/10.x/core-features/data-caching/index.html @@ -4,13 +4,13 @@ Data Caching | Apiato - +
Version: 10.x

Data Caching

Enable / Disable Eloquent Query Caching

info

This feature is disabled By default.

To enable it, go to app/Ship/Configs/repository.php config file and set cache > enabled => true, or set it from the .env file using ELOQUENT_QUERY_CACHE.

More details can be found here.

Users can skip the query caching and request new data by passing specific parameter to the Endpoint. Checkout its documentation here.

Change different caching settings

You can use different cache setting for each repository.

To set cache settings on each repository, first the caching must be enabled, second you need to set some properties on the repository class to override the default values.

For more details about all the properties refer to the L5 repository package documentation.

Note: you don't need to use the CacheableRepository trait or implement the CacheableInterface since they both exist on the Abstract repository class (App\Ship\Parents\Repositories\Repository).

- + \ No newline at end of file diff --git a/docs/10.x/core-features/default-endpoints/index.html b/docs/10.x/core-features/default-endpoints/index.html index ebaa73272..8f2f9f658 100644 --- a/docs/10.x/core-features/default-endpoints/index.html +++ b/docs/10.x/core-features/default-endpoints/index.html @@ -4,13 +4,13 @@ Default Endpoints | Apiato - +
Version: 10.x

Default Endpoints

Apiato comes loaded with many useful API endpoints for speeding up the development process.

You can see the endpoints in three ways:

  • In Terminal, by running php artisan route:list -c.
  • In Browser, by generating the beautiful detailed documentation. See API Docs Generator.
  • In Code, by navigating to the Routes folder of each container's UI.
- + \ No newline at end of file diff --git a/docs/10.x/core-features/etag/index.html b/docs/10.x/core-features/etag/index.html index a8da6ed38..5aa6e381c 100644 --- a/docs/10.x/core-features/etag/index.html +++ b/docs/10.x/core-features/etag/index.html @@ -4,7 +4,7 @@ ETag | Apiato - + @@ -12,7 +12,7 @@
Version: 10.x

ETag

ETag Middleware

Apiato provides an ETag Middleware (app/Ship/Middlewares/Http/ProcessETagHeadersMiddleware.php) that implements the Shallow technique. It can be used to reduce bandwidth on the client side (especially for Mobile devices).

Enable / Disable ETag

info

This feature is disabled By default.

To enable it go to app/Ship/Configs/apiato.php and set use-etag to true. Of course your client should send the If-None-Match HTTP Header (= etag) in his request for this feature to work properly.

- + \ No newline at end of file diff --git a/docs/10.x/core-features/hash-id/index.html b/docs/10.x/core-features/hash-id/index.html index c742ee380..5ec0fcf58 100644 --- a/docs/10.x/core-features/hash-id/index.html +++ b/docs/10.x/core-features/hash-id/index.html @@ -4,13 +4,13 @@ Hash ID | Apiato - +
Version: 10.x

Hash ID

Hashing your internal ID's, is a very helpful feature for security reasons (to prevent some hack attacks) and business reasons (to hide the real total records from your competitors).

Enable Hash ID

Set the HASH_ID=true in the .env file.

Also, with the feature make sure to always use the getHashedKey() on any model, whenever you need to return an ID (mainly from transformers) weather hashed ID or not.

Example:


'id' => $user->getHashedKey(),

Note: if the feature is set to false HASH_ID=false the getHashedKey() will return the normal ID.

Usage

There are 2 ways an ID's can be passed to your system via the API:

In URL example: www.apiato.test/items/abcdef.

In parameters example: [GET] or [POST] www.apiato.test/items?id=abcdef.

in both cases you will need to inform your API about what's coming form the Request class.

Checkout the Requests page. After setting the $decode and $urlParameters properties on your Request class, the ID will be automatically decoded for you to apply validation rules on it or/and use it from your controller. ($request->id will return the decoded ID)

Configuration

You can change the default length and characters used in the ID from the config file app/Ship/Configs/hashids.phpor in the .env file by editing the HASH_ID_LENGTH value.

You can set the HASH_ID_KEY in the .env file to any random string. You can generate this from any of the online random string generators, or run head /dev/urandom | tr -dc 'A-Za-z0-9!"#$%&'\''()*+,-./:;<=>?@[\]^_{|}~' | head -c 32 ; echo on the linux command-line. Apiato defaults to the APP_KEY should this not be set.

The HASH_ID_KEY acts as the salt during hashing of the ID. This should never be changed in production as it renders all previously generated IDs impossible to decode.

Testing

In your tests you must hash the ID's before making the calls, because if you tell your Request class to decode an ID for you, it will throw an exception when the ID is not encoded.

for Parameter ID's

Always use getHashedKey() on your models when you want to get the ID

Example:

$data = [
'roles_ids' => [
$role1->getHashedKey(),
$role2->getHashedKey(),
],
'user_id' => $randomUser->getHashedKey(),
];
$response = $this->makeCall($data);

Or you can do this manually Hashids::encode($id);.

for URL ID's

You can use this helper function injectId($id, $skipEncoding = false, $replace = '{id}').

Example:

$response = $this->injectId($admin->id)->makeCall();

More details on the Tests Helpers page.

Availability

You can use the Apiato\Core\Traits\HashIdTrait on any model or class, in order to have the encode and decode functions.

By default, you have access to these functions $this->encode($id) and $this->decode($id) from all your Test classes and Controllers.

- + \ No newline at end of file diff --git a/docs/10.x/core-features/pagination/index.html b/docs/10.x/core-features/pagination/index.html index b567e0acd..3426fb12d 100644 --- a/docs/10.x/core-features/pagination/index.html +++ b/docs/10.x/core-features/pagination/index.html @@ -4,7 +4,7 @@ Pagination | Apiato - + @@ -16,7 +16,7 @@ you can do it either project wide or per repository. After that a request can get all the data (with no pagination applied) by applying limit=0.

This will return all matching entities:
api.domain.test/endpoint?limit=0

Project Wide

Set PAGINATION_SKIP=true in .env file.

Per Repository

Override the $allowDisablePagination property in your specific Repository class.

note

Per repository configs override the global config and have precedence.

- + \ No newline at end of file diff --git a/docs/10.x/core-features/profiler/index.html b/docs/10.x/core-features/profiler/index.html index 8ad9aa46f..88b98891f 100644 --- a/docs/10.x/core-features/profiler/index.html +++ b/docs/10.x/core-features/profiler/index.html @@ -4,14 +4,14 @@ Profiler | Apiato - +
Version: 10.x

Profiler

Profiling is very important to optimize the performance of your application, and help you better understand what happens when a request is received, as well as it can speed up the debugging process.

Apiato uses the third-party package laravel-debugbar (which uses the PHP Debug Bar), to collect the profiling data.

By default, the laravel-debugbar package displays the profiling data in the browser. However, Apiato uses a middleware app/Ship/Middlewares/Http/ProfilerMiddleware.php to append the profiling data to the response.

Sample Profiler response

{
// Actual Response Here...
"_profiler": {
"__meta": {
"id": "X167f293230e3457f1bbd95d9c82aba4a",
"datetime": "2017-09-22 18:45:27",
"utime": 1506105927.799299,
"method": "GET",
"uri": "/",
"ip": "172.20.0.1"
},
"messages": {
"count": 0,
"messages": []
},
"time": {
"start": 1506105922.742068,
"end": 1506105927.799333,
"duration": 5.057265043258667,
"duration_str": "5.06s",
"measures": [
{
"label": "Booting",
"start": 1506105922.742068,
"relative_start": 0,
"end": 1506105923.524004,
"relative_end": 1506105923.524004,
"duration": 0.7819359302520752,
"duration_str": "781.94ms",
"params": [],
"collector": null
},
{
"label": "Application",
"start": 1506105923.535343,
"relative_start": 0.7932748794555664,
"end": 1506105927.799336,
"relative_end": 0.00000286102294921875,
"duration": 4.26399302482605,
"duration_str": "4.26s",
"params": [],
"collector": null
}
]
},
"memory": {
"peak_usage": 13234248,
"peak_usage_str": "12.62MB"
},
"exceptions": {
"count": 0,
"exceptions": []
},
"route": {
"uri": "GET /",
"middleware": "api, throttle:30,1",
"domain": "http://api.apiato.test",
"as": "apis_root_page",
"controller": "App\\Containers\\Welcome\\UI\\API\\Controllers\\Controller@apiRoot",
"namespace": "App\\Containers\\Welcome\\UI\\API\\Controllers",
"prefix": "/",
"where": [],
"file": "app/Containers/Welcome/UI/API/Controllers/Controller.php:20-25"
},
"queries": {
"nb_statements": 0,
"nb_failed_statements": 0,
"accumulated_duration": 0,
"accumulated_duration_str": "0μs",
"statements": []
},
"swiftmailer_mails": {
"count": 0,
"mails": []
},
"logs": {
"count": 3,
"messages": [
{
"message": "...",
"message_html": null,
"is_string": false,
"label": "error",
"time": 1506105927.694807
},
{
"message": "...",
"message_html": null,
"is_string": false,
"label": "error",
"time": 1506105927.694811
},
{
"message": "[2017-09-18 17:38:15] testing.INFO: New User registration. ID = 970ylqvaogmxnbdr | Email = apiato@mail.test. Thank you for signing up.\n</div>\n</body>\n</html>\n \n",
"message_html": null,
"is_string": false,
"label": "info",
"time": 1506105927.694812
}
]
},
"auth": {
"guards": {
"web": "array:2 [\n \"name\" => \"Guest\"\n \"user\" => array:1 [\n \"guest\" => true\n ]\n]",
"api": "array:2 [\n \"name\" => \"Guest\"\n \"user\" => array:1 [\n \"guest\" => true\n ]\n]"
},
"names": ""
},
"gate": {
"count": 0,
"messages": []
}
}
}

Configuration

By default, the profiler feature is turned off. To turn it on edit the .env file and set DEBUGBAR_ENABLED=true.

To control and modify the profiler response, you need to edit this config file app/Ship/Configs/debugbar.php.

- + \ No newline at end of file diff --git a/docs/10.x/core-features/query-parameters/index.html b/docs/10.x/core-features/query-parameters/index.html index c5762f3f1..6023c5ea9 100644 --- a/docs/10.x/core-features/query-parameters/index.html +++ b/docs/10.x/core-features/query-parameters/index.html @@ -4,7 +4,7 @@ Query Parameters | Apiato - + @@ -25,7 +25,7 @@ accepts driver as relationship ($availableIncludes in Transformer).

Nested Includes

It is also possible to request "nested includes". Extend the example from above. Imagine, that a Driver may also have a relationship to an Address object. You can access this information as well by calling ?include=driver,driver.address.

Of course, the address include is defined in the respective DriverTransformer that is used here.

Where to define the includes:

Every Transformer can have 2 types of includes $availableIncludes and $defaultIncludes:

    protected $availableIncludes = [
'products',
'store',
'recipients',
];

protected $defaultIncludes = [
'invoice',
];

$defaultIncludes will not be listed in the response, only the $availableIncludes will be.

Visit the Transformers page for more details.

Skip caching

(provided by the L5 Repository)

Note: You need to turn the Eloquent Query Caching ON for this feature to work. ELOQUENT_QUERY_CACHE=true in .env.

To run a new query and force disabling the cache on certain endpoints, you can use this parameter

?skipCache=true

It's not recommended to keep skipping cache as it has bad impact on the performance.

Configuration

Most of these parameters are provided by the L5 Repository and configurable from the Ship/Configs/repository.php file. Some of them are built in house, or inherited from other packages such as Fractal.

See the Query parameters from the User Developer perspective

1) Generate the Default API documentation

2) Visit the documentation URL

More details in the API Docs Generator page.

More Information

For more details on these parameters check out these links:

- + \ No newline at end of file diff --git a/docs/10.x/core-features/rate-limiting/index.html b/docs/10.x/core-features/rate-limiting/index.html index 57c7aa16e..d3584f80d 100644 --- a/docs/10.x/core-features/rate-limiting/index.html +++ b/docs/10.x/core-features/rate-limiting/index.html @@ -4,14 +4,14 @@ Rate Limiting | Apiato - +
Version: 10.x

Rate Limiting

Apiato uses the default Laravel middleware for rate limiting (throttling).

All REST API requests are throttled to prevent abuse and ensure stability. The exact number of calls that your application can make per day varies based on the type of request you are making.

The rate limit window is 1 minute per endpoint, with most individual calls allowing for 30 requests in each window.

In other words, each user is allowed to make 30 calls per endpoint every 1 minute. (For each unique access token).

To update these values go to app/Ship/Configs/apiato.php config file, or to the ENV file.

'throttle' => [
'enabled' => env('API_RATE_LIMIT_ENABLED', true),
'attempts' => env('API_RATE_LIMIT_ATTEMPTS', '30'),
'expires' => env('API_RATE_LIMIT_EXPIRES', '1'),
]
API_RATE_LIMIT_ENABLED=true
API_RATE_LIMIT_ATTEMPTS=30
API_RATE_LIMIT_EXPIRES=1

For how many hits you can preform on an endpoint, you can always check the header:

X-RateLimit-Limit →30
X-RateLimit-Remaining →29

Enable/Disable Rate Limiting:

The API rate limiting middleware is enabled and applied to all the Container Endpoints by default.

To disable it set API_RATE_LIMIT_ENABLED to false in the .env file.

- + \ No newline at end of file diff --git a/docs/10.x/core-features/useful-commands/index.html b/docs/10.x/core-features/useful-commands/index.html index 4faa5c00a..78d41546f 100644 --- a/docs/10.x/core-features/useful-commands/index.html +++ b/docs/10.x/core-features/useful-commands/index.html @@ -4,14 +4,14 @@ Useful Commands | Apiato - +
Version: 10.x

Useful Commands

Apiato is loaded with many useful commands to help you speed up the development process. You can see list of all commands, by typing php artisan and look for Apiato section.

Available Commands

  • php artisan apiato Display the current Apiato version.
  • php artisan apiato:apidoc Generate API Documentations with apidoc from your routes Docblock. More details.
  • php artisan apiato:create:admin Create a new User with the ADMIN role
  • php artisan apiato:generate:{component} Generate a specific component for the framework (e.g., Action, Task, ...). For more details on the Code Generator click here.
  • php artisan apiato:list:actions List all Actions in the Application.
  • php artisan apiato:list:tasks List all Tasks in the Application.
  • php artisan apiato:permissions:toRole Give all system Permissions to a specific Role.
  • php artisan apiato:seed-deploy Seeds your custom deployment data from app/Ship/Seeders/SeedDeploymentData.php.
  • php artisan apiato:seed-test Seeds your custom testing data from app/Ship/Seeders/SeedTestingData.php.
  • php artisan apiato:welcome Just saying welcome from a container.
- + \ No newline at end of file diff --git a/docs/10.x/core-features/user-registration/index.html b/docs/10.x/core-features/user-registration/index.html index 961bd779c..4489698fa 100644 --- a/docs/10.x/core-features/user-registration/index.html +++ b/docs/10.x/core-features/user-registration/index.html @@ -4,13 +4,13 @@ User Registration | Apiato - +
Version: 10.x

User Registration

Register users by credentials (email and passwords)

Call the http://api.apiato.test/v1/register endpoint (you can find its documentation after generating the API Docs.

Check out the registerUser endpoint in the API Routes files.

This will register a new User and respond with user object.

Registration request:

curl --request POST \
--url http://api.apiato.test/v1/register \
--header 'accept: application/json' \
--header 'content-type: application/x-www-form-urlencoded' \
--data 'email=john%40doe.com&password=password&name=John%20Doe'

Registration response:

{
"data": {
"object": "User",
"id": "XbPW7awNkzl83LD6",
"name": "John Doe",
"email": "john@doe.com",
"email_verified_at": null,
"gender": null,
"birth": null,
"created_at": "2021-04-15T14:17:24.000000Z",
"updated_at": "2021-04-15T14:17:24.000000Z",
"readable_created_at": "1 second ago",
"readable_updated_at": "1 second ago"
},
"meta": {
"include": [
"roles"
],
"custom": []
}
}

Note: After registration in order to get the user access token you will have to send another call to http://api.example.com/v1/oauth/token with following fields and values

username => your_username e.g. admin@admin.com
password => your_password
grant_type => password
client_id => your_client_id
client_secret => your_client_secret

For third-party clients you must have client ID and secret first. You can generate them by creating new client in your app using Laravel Passport.

For first-party clients you can use a proxy to add those fields on requests coming from your trusted client. For an example on how to do it look at ProxyLoginForWebClientAction Action in Authentication Container.

Register users by Social Account

(Facebook, Twitter, Google..)

Checkout the Social Authentication Page for how to Sign up with Social Account.

- + \ No newline at end of file diff --git a/docs/10.x/core-features/validation/index.html b/docs/10.x/core-features/validation/index.html index ee8606e61..bcaae678d 100644 --- a/docs/10.x/core-features/validation/index.html +++ b/docs/10.x/core-features/validation/index.html @@ -4,13 +4,13 @@ Validation | Apiato - +
Version: 10.x

Validation

Apiato uses the powerful Laravel validation system.

In Apiato, validation must be defined in Request component, since every request might have different rules.

Validation rules are automatically applied, once injecting the Request in the Controller.

Requests help validating User data, accessibility, ownership and more.

Example Request with Validation rules:

namespace App\Containers\AppSection\User\UI\API\Requests;

use App\Ship\Parents\Requests\Request;

class RegisterUserRequest extends Request
{
/**
* @return array
*/
public function rules()
{
return [
'email' => 'required|email|max:200|unique:users,email',
'password' => 'required|min:20|max:300',
'name' => 'required|min:2|max:400',
];
}

}

Usage from Controller Example:

    public function registerUser(RegisterUserRequest $request)
{
$user = app(RegisterUserAction::class)->run($request);
return $this->transform($user, UserTransformer::class);
}

Responses

Validation Error response format:

Single Field:

{
"message": "The given data was invalid.",
"errors": {
"email": [
"The email has already been taken."
]
}
}

Multiple Fields:

{
"message": "The given data was invalid.",
"errors": {
"email": [
"The email has already been taken."
],
"password": [
"The password field is required."
]
}
}

More details about requests in the Requests Page.

- + \ No newline at end of file diff --git a/docs/10.x/faq/index.html b/docs/10.x/faq/index.html index eb750c57d..f7e1ab35b 100644 --- a/docs/10.x/faq/index.html +++ b/docs/10.x/faq/index.html @@ -4,7 +4,7 @@ Frequently Asked Questions | Apiato - + @@ -37,7 +37,7 @@ Discord.

Lastly, if you got your question answered, consider sharing it, if you believe it can help others. You can submit a PR adding the questions and answer here on the FAQ page. Or leave it somewhere on the repository or on the chat room. Thanks in advance :)

- + \ No newline at end of file diff --git a/docs/10.x/getting-started/container-installer/index.html b/docs/10.x/getting-started/container-installer/index.html index 273d23ce2..3d8d8127d 100644 --- a/docs/10.x/getting-started/container-installer/index.html +++ b/docs/10.x/getting-started/container-installer/index.html @@ -4,7 +4,7 @@ Container Installer | Apiato - + @@ -20,7 +20,7 @@ that allows installing/updating containers.
  • You must provide the key extra.apiato.container.name. This key indicates the name of the folder (e.g., container) when installing the package to the /app/ContainersVendorSection folder. In the shown example, the container would be installed to app/Containers/VendorSection/Foo.
  • - + \ No newline at end of file diff --git a/docs/10.x/getting-started/conventions-and-principles/index.html b/docs/10.x/getting-started/conventions-and-principles/index.html index a27fe4a85..e02d8e98b 100644 --- a/docs/10.x/getting-started/conventions-and-principles/index.html +++ b/docs/10.x/getting-started/conventions-and-principles/index.html @@ -4,13 +4,13 @@ Conventions | Apiato - +
    Version: 10.x

    Conventions

    HTTP Methods usage in RESTful API's

    • GET (SELECT): retrieve a specific resource from the server, or a listing of resources.
    • POST (CREATE): create a new resource on the server.
    • PUT (UPDATE): update a resource on the server, providing the entire resource.
    • PATCH (UPDATE): update a resource on the server, providing only changed attributes.
    • DELETE (DELETE): remove a resource from the server.

    Naming Conventions for Routes & Actions

    • GetAllResource: to fetch all resources.
    • FindResourceByID: to search for single resource by its unique identifier.
    • CreateResource: to create a new resource.
    • UpdateResource: to update/edit existing resource.
    • DeleteResource: to delete a resource.

    General guidelines and principles for RESTful URLs

    • A URL identifies a resource.
    • URLs should include nouns, not verbs.
    • Use plural nouns only for consistency (no singular nouns).
    • Use HTTP verbs (GET, POST, PUT, DELETE) to operate on the collections and elements.
    • You should not need to go deeper than resource/identifier/resource.
    • Put the version number at the base of your URL, for example http://apiato.test/v1/path/to/resource.
    • If an input data changes the logic of the endpoint, it should be passed in the URL. If not can go in the header "like Auth Token".
    • Don't use query parameters to alter state.
    • Don't use mixed-case paths if you can help it; lowercase is best.
    • Don't use implementation-specific extensions in your URIs (.php, .py, .pl, etc.)
    • Limit your URI space as much as possible. And keep path segments short.
    • Don't put metadata in the body of a response that should be in a header

    Good URL examples

    • Find a single Car by its unique identifier (ID):
      • GET http://www.api.apiato.test/v1/cars/123
    • Get all Cars:
      • GET http://www.api.apiato.test/v1/cars
    • Find/Search cars by one or more fields:
      • GET http://www.api.apiato.test/v1/cars?search=maker:mercedes
      • GET http://www.api.apiato.test/v1/cars?search=maker:mercedes;color:white
    • Order and Sort query result:
      • GET http://www.api.apiato.test/v1/cars?orderBy=created_at&sortedBy=desc
      • GET http://www.api.apiato.test/v1/cars?search=maker:mercedes&orderBy=created_at&sortedBy=desc
    • Specify optional fields:
      • GET http://www.api.apiato.test/v1/cars?filter=id;name;status
      • GET http://www.api.apiato.test/v1/cars/123?filter=id;name;status
    • Get all Drivers belonging to a Car:
      • GET http://www.api.apiato.test/v1/cars/123/drivers
      • GET http://www.api.apiato.test/v1/cars/123/drivers/123/addresses
    • Include Drivers objects relationship with the car response:
      • GET http://www.api.apiato.test/v1/cars/123?include=drivers
      • GET http://www.api.apiato.test/v1/cars/123?include=drivers,owner
    • Add new Car:
      • POST http://www.api.apiato.test/v1/cars
    • Add new Driver to a Car:
      • POST http://www.api.apiato.test/v1/cars/123/drivers

    General principles for HTTP methods

    • Don't ever use GET to alter state; to prevent Googlebot from corrupting your data. And use GET as much as possible.
    • Don't use PUT unless you are updating an entire resource. And unless you can also legitimately do a GET on the same URI.
    • Don't use POST to retrieve information that is long-lived or that might be reasonable to cache.
    • Don't perform an operation that is not idempotent with PUT.
    • Use GET for things like calculations, unless your input is large, in which case use POST.
    • Use POST in preference to PUT when in doubt.
    • Use POST whenever you have to do something that feels RPC-like.
    • Use PUT for classes of resources that are larger or hierarchical.
    • Use DELETE in preference to POST to remove resources.
    - + \ No newline at end of file diff --git a/docs/10.x/getting-started/installation/index.html b/docs/10.x/getting-started/installation/index.html index 1beeb6a29..33aeabc3c 100644 --- a/docs/10.x/getting-started/installation/index.html +++ b/docs/10.x/getting-started/installation/index.html @@ -4,7 +4,7 @@ Installation | Apiato - + @@ -29,7 +29,7 @@ try running this command homestead halt && homestead up --provision.

    Using anything else

    If you're not into virtualization solutions, you can set up your environment directly on your machine. Check the software's requirements list.

    Let's Play

    Now let's see it in action

    Open your web browser and visit:

    • http://apiato.test You should see an HTML page, with Apiato in the middle.
    • http://api.apiato.test You should see a response like this:
    [
    "Welcome to Apiato"
    ]

    Open your HTTP client and call:

    • http://api.apiato.test/ You should see a JSON response with message: "Welcome to apiato.",
    • http://api.apiato.test/v1 You should see a JSON response with message: "Welcome to apiato (API V1).",

    Make some HTTP calls to the API:

    To make the calls you can use Postman, HTTPIE or any other tool you prefer.

    Let's test the (user registration) endpoint http://api.apiato.test/v1/register with cURL:

    curl -X POST -H "Accept: application/json" -H "Cache-Control: no-cache" -F "email=John@Doe.me" -F "password=so-secret" -F "name=John Doe" "http://api.apiato.test/v1/register"

    You should get a response like this:

    Header:

    Access-Control-Allow-Origin → ...
    Cache-Control → ...
    Connection → keep-alive
    Content-Language → en
    Content-Type → application/json
    Date → Wed, 11 Apr 2000 22:55:88 GMT
    Server → nginx
    Transfer-Encoding → chunked
    Vary → Origin
    X-Powered-By → PHP/7.7.7
    X-RateLimit-Limit → 30
    X-RateLimit-Remaining → 29

    Body:

    {
    "data": {
    "object": "User",
    "id": "7VgmkMw7rR2pWO5j",
    "name": "John Doe",
    "email": "John@Doe.me",
    "email_verified_at": null,
    "gender": null,
    "birth": null,
    "created_at": "2021-04-12T13:33:24.000000Z",
    "updated_at": "2021-04-12T13:33:24.000000Z",
    "readable_created_at": "1 second ago",
    "readable_updated_at": "1 second ago"
    },
    "meta": {
    "include": [
    "roles"
    ],
    "custom": []
    }
    }
    - + \ No newline at end of file diff --git a/docs/10.x/getting-started/markdown-features/index.html b/docs/10.x/getting-started/markdown-features/index.html index c66a38afe..c1967174d 100644 --- a/docs/10.x/getting-started/markdown-features/index.html +++ b/docs/10.x/getting-started/markdown-features/index.html @@ -4,13 +4,13 @@ Markdown Features | Apiato - +
    Version: 10.x

    Markdown Features

    Docusaurus supports the Markdown syntax and has some additional features.

    Front Matter

    Markdown documents can have associated metadata at the top called Front Matter:

    ---
    id: my-doc
    title: My document title
    description: My document description
    sidebar_label: My doc
    ---

    Markdown content

    Regular Markdown links are supported using url paths or relative file paths.

    Let's see how to [Create a page].
    Let's see how to [Create a page].

    Let's see how to [Create a page].

    Markdown images

    Regular Markdown images are supported.

    Add an image at static/img/logo.png and use this Markdown declaration:

    ![Docusaurus logo](/img/logo.png)

    Docusaurus logo

    Code Blocks

    Markdown code blocks are supported with Syntax highlighting.

    ```jsx title="src/components/HelloDocusaurus.js"
    function HelloDocusaurus() {
    return (
    <h1>Hello, Docusaurus!</h1>
    )
    }
    ```
    src/components/HelloDocusaurus.js
    function HelloDocusaurus() {
    return <h1>Hello, Docusaurus!</h1>;
    }

    Admonitions

    Docusaurus has a special syntax to create admonitions and callouts:

    :::tip My tip

    Use this awesome feature option

    :::

    :::danger Take care

    This action is dangerous

    :::
    My tip

    Use this awesome feature option

    Take care

    This action is dangerous

    React components

    Thanks to MDX, you can make your doc more interactive and use React components inside Markdown:

    export const Highlight = ({children, color}) => (
    <span
    style={{
    backgroundColor: color,
    borderRadius: '2px',
    color: 'red',
    padding: '0.2rem',
    }}>
    {children}
    </span>
    );

    <Highlight color="#25c2a0">Docusaurus green</Highlight> and <Highlight color="#1877F2">Facebook blue</Highlight> are my favorite colors.
    Docusaurus green and Facebook blue are my favorite colors.
    - + \ No newline at end of file diff --git a/docs/10.x/getting-started/requests/index.html b/docs/10.x/getting-started/requests/index.html index d0c5eeea0..c7d0eb02d 100644 --- a/docs/10.x/getting-started/requests/index.html +++ b/docs/10.x/getting-started/requests/index.html @@ -4,7 +4,7 @@ Requests | Apiato - + @@ -17,7 +17,7 @@ you can force your users to send application/json by setting 'force-accept-header' => true, in app/Ship/Configs/apiato.php or allow them to skip it completely by setting the 'force-accept-header' => false,. By default this flag is set to false.

    Calling Endpoints

    Calling unprotected endpoint example:

    curl -X POST -H "Accept: application/json" -H "Content-Type: application/x-www-form-urlencoded; -F "email=admin@admin.com" -F "password=admin" -F "=" "http://api.domain.test/v2/register"

    Calling protected endpoint (passing Bearer Token) example:

    curl -X GET -H "Accept: application/json" -H "Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9..." -H "http://api.domain.test/v1/users"
    - + \ No newline at end of file diff --git a/docs/10.x/getting-started/responses/index.html b/docs/10.x/getting-started/responses/index.html index a0105219a..7d8182616 100644 --- a/docs/10.x/getting-started/responses/index.html +++ b/docs/10.x/getting-started/responses/index.html @@ -4,7 +4,7 @@ Responses | Apiato - + @@ -17,7 +17,7 @@ If no $resourceKey is defined at the Model, the ShortClassName is used as key. For example, the ShortClassName of the App\Containers\AppSection\User\Models\User::class is User.

    Error Responses formats

    Visit each feature, e.g. the Authentication and there you will see how an unauthenticated response looks like, same for Authorization, Validation and so on.

    Building a Responses from the Controller:

    Checkout the Controller response builder helper functions.

    - + \ No newline at end of file diff --git a/docs/10.x/getting-started/samples/index.html b/docs/10.x/getting-started/samples/index.html index 84d3b5207..ea2798166 100644 --- a/docs/10.x/getting-started/samples/index.html +++ b/docs/10.x/getting-started/samples/index.html @@ -4,7 +4,7 @@ Samples | Apiato - + @@ -12,7 +12,7 @@
    Version: 10.x

    Samples

    The basic flow

    When an HTTP request is received, it first hits your predefined Endpoint (each endpoint live in its own Route file).

    Sample Route Endpoint

    Route::get('/hello', [Controller::class, 'sayHello']);

    After the user makes a request to the endpoint [GET] www.api.apiato.com/v1/hello it calls the defined controller function (sayHello).

    Sample Controller Function

    class Controller extends ApiController
    {
    public function sayHello(SayHelloRequest $request)
    {
    $helloMessage = app(SayHelloAction::class)->run();

    $this->json([
    $helloMessage
    ]);
    }
    }

    This function takes a Request class SayHelloRequest to automatically checks if the user has the right access to this endpoint. Only if the user has access, it proceeds to the function body.

    Then the function calls an Action (SayHelloAction) to perform the business logic.

    Sample Action

    class SayHelloAction extends Action
    {
    public function run()
    {
    return 'Hello World!';
    }
    }

    The Action can do anything then return a result (could be an Object, a String or anything).

    When the Action finishes its job, the controller function gets ready to build a response.

    Json responses can be built using the helper function json ($this->json(['foo' => 'bar']);).

    Sample User Response

    [
    "Hello World!"
    ]
    - + \ No newline at end of file diff --git a/docs/10.x/getting-started/software-architectural-patterns/index.html b/docs/10.x/getting-started/software-architectural-patterns/index.html index 19dd4c111..35f6ef505 100644 --- a/docs/10.x/getting-started/software-architectural-patterns/index.html +++ b/docs/10.x/getting-started/software-architectural-patterns/index.html @@ -4,7 +4,7 @@ Architecture | Apiato - + @@ -14,7 +14,7 @@ App\Containers\SectionName\Printer).
  • Container MAY be named anything, however a good practice is to name it to its most important Model name. Example: If the User Story is (User can create a Store and Store can have Items) then we you could have 3 Containers (User, Store and Item).
  • - + \ No newline at end of file diff --git a/docs/10.x/index.html b/docs/10.x/index.html index 04d36198b..e32b20abc 100644 --- a/docs/10.x/index.html +++ b/docs/10.x/index.html @@ -4,13 +4,13 @@ Requirements | Apiato - +
    Version: 10.x

    Requirements

    Requirements

    • GIT
    • PHP >= 7.4 (8.0 is recommended)
    • Composer
    • PHP Extensions:
      • OpenSSL PHP Extension
      • PDO PHP Extension
      • Mbstring PHP Extension
      • Tokenizer PHP Extension
      • BCMath PHP Extension (required when the Hash ID feature is enabled)
      • Intl Extension (required when you use the Localization Container)
    - + \ No newline at end of file diff --git a/docs/10.x/main-components/actions/index.html b/docs/10.x/main-components/actions/index.html index ee6be876d..a54a7a811 100644 --- a/docs/10.x/main-components/actions/index.html +++ b/docs/10.x/main-components/actions/index.html @@ -4,13 +4,13 @@ Actions | Apiato - +
    Version: 10.x

    Actions

    Definition & Principles

    Read Porto SAP Documentation (#Actions).

    Rules

    • All Actions MUST extend App\Ship\Parents\Actions\Action.

    Folder Structure

     - app
    - Containers
    - {section-name}
    - {container-name}
    - Actions
    - CreateUserAction.php
    - DeleteUserAction.php
    - ...

    Code Sample

    Action

    class CreateAdminAction extends Action
    {
    public function run(string $email, string $password, string $name, bool $isClient = false): User
    {
    $admin = app(CreateUserByCredentialsTask::class)->run(
    $isClient,
    $email,
    $password,
    $name
    );

    app(AssignUserToRoleTask::class)->run($admin, ['admin']);

    return $admin;
    }
    }

    Calling multiple Tasks

    class DemoAction extends Action
    {
    public function run($xxx, $yyy, $zzz)
    {
    $foo = app(Sample111Task::class)->run($xxx, $yyy);
    $bar = app(Sample222Task::class)->run($zzz);
    }
    }

    Usage from a Controller

        public function deleteUser(DeleteUserRequest $request)
    {
    $user = app(DeleteUserAction::class)->run($request);
    return $this->deleted($user);
    }
    tip

    The same Action MAY be called by multiple Controllers (Web, Api, Cli).

    - + \ No newline at end of file diff --git a/docs/10.x/main-components/controllers/index.html b/docs/10.x/main-components/controllers/index.html index b3ccf78f2..770e774a5 100644 --- a/docs/10.x/main-components/controllers/index.html +++ b/docs/10.x/main-components/controllers/index.html @@ -4,7 +4,7 @@ Controllers | Apiato - + @@ -17,7 +17,7 @@ This function allows including metadata in the response.

    $metaData = ['total_credits', 10000];

    return $this->withMeta($metaData)->transform($receipt, ReceiptTransformer::class);

    json This function allows passing array data to be represented as json.

    return $this->json([
    'foo': 'bar'
    ])

    Other functions

    • accepted
    • deleted
    • noContent
    • // Some functions might not be documented, so refer to the vendor/apiato/core/Traits/ResponseTrait.php and see the public functions.
    - + \ No newline at end of file diff --git a/docs/10.x/main-components/exceptions/index.html b/docs/10.x/main-components/exceptions/index.html index 8db119010..12c7ca767 100644 --- a/docs/10.x/main-components/exceptions/index.html +++ b/docs/10.x/main-components/exceptions/index.html @@ -4,13 +4,13 @@ Exceptions | Apiato - +
    Version: 10.x

    Exceptions

    Definition & Principles

    Read Porto SAP Documentation (#Exceptions).

    Rules

    • All Exceptions MUST extend App\Ship\Parents\Exceptions\Exception.
    • Shared (general) Exceptions between all Containers SHOULD be created in the Exceptions Ship folder (app/Ship/Exceptions/*).
    • Every Exception SHOULD have two properties code and message. You can override those values while throwing the error.

    Folder Structure

     - App
    - Containers
    - {section-name}
    - {container-name}
    - Exceptions
    - AccountFailedException.php
    - ...

    - Ship
    - Exceptions
    - CreateResourceFailedException.php
    - NotFoundException.php
    - ...

    Code Samples

    Demo Exception

    class DemoException extends Exception
    {
    public $code = Response::HTTP_CONFLICT;
    public $message = 'This is a demo exception.';
    }

    Usage from anywhere

    throw new AccountFailedException();

    Usage with errors

    throw (new AccountFailedException())->withErrors(['email' => 'Email already in use']);
    throw (new AccountFailedException())->withErrors(['email' => ['Email already in use', 'Another message']]);

    Usage with errors and localization

    For localization, you can use the Localization Container

    // translation strings are automatically translated if the translations are found.
    throw (new AccountFailedException())->withErrors(['email' => 'appSection@user::exceptions.email-taken']);

    Response:

    {
    "message": "The exception error message.",
    "errors": {
    "email": [
    "The email has already been taken."
    ]
    }
    }

    Usage with Log for Debugging

    throw (new AccountFailedException())->debug($e); // debug() accepts string or \Exception instance

    Usage and overriding the default

    throw new AccountFailedException('I am the message to be displayed to the user');
    - + \ No newline at end of file diff --git a/docs/10.x/main-components/models/index.html b/docs/10.x/main-components/models/index.html index 4375217d5..5ba664018 100644 --- a/docs/10.x/main-components/models/index.html +++ b/docs/10.x/main-components/models/index.html @@ -4,13 +4,13 @@ Models | Apiato - +
    Version: 10.x

    Models

    Definition & Principles

    Read Porto SAP Documentation (#Models).

    Rules

    • All Models MUST extend from App\Ship\Parents\Models\Model.
    • If the name of a model differs from the Container name you have to implement model() method in the repository - more details.

    Folder Structure

     - App
    - Containers
    - {section-name}
    - {container-name}
    - Models
    - User.php
    - UserId.php
    - ...

    Code Sample

    class Demo extends Model
    {
    protected $table = 'demos';

    protected $fillable = [
    'label',
    'user_id'
    ];

    protected $hidden = [
    'token',
    ];

    protected $casts = [
    'total_credits' => 'float',
    ];

    protected $dates = [
    'created_at',
    'updated_at',
    ];

    public function user()
    {
    return $this->belongsTo(\App\Containers\AppSection\User\Models\User::class);
    }
    }

    Notice the Demo Model has a relationship with User Model, which lives in another Container.

    Casts

    The casts attribute can be used to parse any of the model's attributes to a specific type. In the code sample below we can cast total_credits to float.

    More information about the applicable cast-types can be found in the laravel eloquent-mutators documentation.

    You can place any dates inside the $dates to parse those automatically.

    - + \ No newline at end of file diff --git a/docs/10.x/main-components/requests/index.html b/docs/10.x/main-components/requests/index.html index 84e26f37d..a06236ba0 100644 --- a/docs/10.x/main-components/requests/index.html +++ b/docs/10.x/main-components/requests/index.html @@ -4,7 +4,7 @@ Requests | Apiato - + @@ -25,7 +25,7 @@ function.

    This helper, in turn, allows to "redefine" keys in the request for subsequent processing. Consider the following example request:

    {
    "data" : {
    "name" : "John Doe"
    }
    }

    Your Task to process this data, however, requests the field data.name as data.username. You can call the helper like this:

    $request->mapInput([
    'data.name' => 'data.username',
    ]);

    The resulting structure would look like this:

    {
    "data" : {
    "username" : "John Doe"
    }
    }

    Storing Data on the Request

    During the Request life-cycle you may want to store some data on the request object and pass it to other SubActions (or Tasks).

    To store some data on the request use:

    $request->keep(['someKey' => $someValue]);

    To retrieve the data back at any time during the request life-cycle use:

    $someValue = $request->retrieve('someKey');

    Unit Testing for Actions (Request)

    Since we're passing Request objects to Actions. When writing unit tests we need to create fake Request just to pass it to the Action with some fake data.

    // creating
    $request = RegisterUserRequest::injectData($data);

    Example One:

    $data = [
    'email' => 'john@doe.test',
    'name' => 'John Doe',
    'password' => 'so-secret',
    ];

    // create request object with some data
    $request = RegisterUserRequest::injectData($data);

    // create instance of the Action
    $action = app(RegisterUserAction::class)->run($request);

    // do any kind of assertions..
    $this->assertInstanceOf(User::class, $user);

    Example Two (With Authenticated User):

    $data = [
    'store_id' => $this->encode($store->id),
    'items' => $orderItems,
    'recipient' => $receipient,
    ];

    $user = User::factory()->create();

    $request = MakeOrderRequest::injectData($data, $user);

    $order = app(MakeOrderAction::class)->run($request);
    - + \ No newline at end of file diff --git a/docs/10.x/main-components/routes/index.html b/docs/10.x/main-components/routes/index.html index 1989d5c46..89eb656fe 100644 --- a/docs/10.x/main-components/routes/index.html +++ b/docs/10.x/main-components/routes/index.html @@ -4,13 +4,13 @@ Routes | Apiato - +
    Version: 10.x

    Routes

    Definition & Principles

    Read Porto SAP Documentation (#Routes).

    Rules

    • API Route files MUST be named according to their API's version, exposure and functionality. e.g. CreateOrder.v1.public.php, FulfillOrder.v2.public.php, CancelOrder.v1.private.php...

    • Web Route files are pretty similar to API web files, but they can be named anything.

    Folder Structure

     - app
    - Containers
    - {section-name}
    - {container-name}
    - UI
    - API
    - Routes
    - CreateItem.v1.public.php
    - DeleteItem.v1.public.php
    - CreateItem.v2.public.php
    - DeleteItem.v1.private.php
    - ApproveItem.v1.private.php
    - ...
    - WEB
    - Routes
    - main.php
    - ...

    Code Sample

    Web & API route

    Routes are defined exactly like the way you defined them in Laravel.

    Route::post('hello', [Controller::class, 'sayHello']);

    Protected Route (API)

    Route::get('users', [Controller::class, 'listAllUsers'])
    ->middleware(['auth:api']);

    Protect your Endpoints:

    Checkout the Authorization Page.

    Difference between Public & Private routes files

    Apiato has 2 types of endpoint, Public (External) mainly for third parties clients, and Private (Internal) for your own Apps. This will help to generate separate documentations for each and keep your internal API private.

    - + \ No newline at end of file diff --git a/docs/10.x/main-components/subactions/index.html b/docs/10.x/main-components/subactions/index.html index 88d658e71..79eae79af 100644 --- a/docs/10.x/main-components/subactions/index.html +++ b/docs/10.x/main-components/subactions/index.html @@ -4,13 +4,13 @@ Sub Actions | Apiato - +
    Version: 10.x

    Sub Actions

    Definition & Principles

    Read Porto SAP Documentation (#Sub-Actions).

    Rules

    • All SubActions MUST extend from App\Ship\Parents\Actions\SubAction.

    Folder Structure

     - app
    - Containers
    - {section-name}
    - {container-name}
    - Actions
    - ValidateAddressSubAction.php
    - BuildOrderSubAction.php
    - ...

    Code Sample

    ExampleSubAction

    class ExampleSubAction extends SubAction
    {
    public function run(SomeRequest $request)
    {
    app(SomeTask::class)->run($request);
    }
    }
    note

    Every feature available for Actions, are also available in SubActions.

    - + \ No newline at end of file diff --git a/docs/10.x/main-components/tasks/index.html b/docs/10.x/main-components/tasks/index.html index 385676d9a..985ef3391 100644 --- a/docs/10.x/main-components/tasks/index.html +++ b/docs/10.x/main-components/tasks/index.html @@ -4,13 +4,13 @@ Tasks | Apiato - +
    Version: 10.x

    Tasks

    Definition & Principles

    Read Porto SAP Documentation (#Tasks).

    Rules

    • All Tasks MUST extend from App\Ship\Parents\Tasks\Task.

    Folder Structure

     - app
    - Containers
    - {section-name}
    - {container-name}
    - Tasks
    - ConfirmUserEmailTask.php
    - GenerateEmailConfirmationUrlTask.php
    - SendConfirmationEmailTask.php
    - ValidateConfirmationCodeTask.php
    - SetUserEmailTask.php
    - ...

    Code Sample

    Task

    class FindUserByIdTask extends Task
    {
    private $userRepository;

    public function __construct(UserRepository $userRepository)
    {
    $this->userRepository = $userRepository;
    }

    public function run($id)
    {
    try {
    $user = $this->userRepository->find($id);
    } catch (Exception $e) {
    throw new UserNotFoundException();
    }

    return $user;
    }
    }

    Task usage from an Action

    class ValidateUserEmailByConfirmationCodeAction extends Action
    {
    public function run($userId, $code)
    {
    app(ValidateConfirmationCodeTask::class)->run($userId, $code);
    $user = app(FindUserByIdTask::class)->run($userId);
    app(ConfirmUserEmailTask::class)->run($user);
    }
    }
    - + \ No newline at end of file diff --git a/docs/10.x/main-components/transformers/index.html b/docs/10.x/main-components/transformers/index.html index 99a7608b7..8d5015ba0 100644 --- a/docs/10.x/main-components/transformers/index.html +++ b/docs/10.x/main-components/transformers/index.html @@ -4,13 +4,13 @@ Transformers | Apiato - +
    Version: 10.x

    Transformers

    Definition & Principles

    Read Porto SAP Documentation (#Transformers).

    Rules

    • All API responses MUST be formatted via a Transformer.

    • Every Transformer SHOULD extend from App\Ship\Parents\Transformers\Transformer.

    • Each Transformer MUST have a transform() function.

    Folder Structure

     - app
    - Containers
    - {section-name}
    - {container-name}
    - UI
    - API
    - Transformers
    - UserTransformer.php
    - ...

    Code Samples

    Reward Transformer with Country relation

    class ItemTransformer extends Transformer
    {
    protected $availableIncludes = [
    'images',
    ];

    protected $defaultIncludes = [
    'roles',
    ];

    public function transform(Item $item)
    {
    $response = [
    'object' => $item->getResourceKey(),
    'id' => $item->getHashedKey(),
    'name' => $item->name,
    'description' => $item->description,
    'price' => (float)$item->price,
    'weight' => (float)$item->weight,
    'created_at' => $item->created_at,
    'updated_at' => $item->updated_at,
    'readable_created_at' => $item->created_at->diffForHumans(),
    'readable_updated_at' => $item->updated_at->diffForHumans(),
    ];

    // add more or modify data for Admins only
    $response = $this->ifAdmin([
    'real_id' => $item->id,
    'deleted_at' => $item->deleted_at,
    ], $response);

    return $response;
    }

    public function includeImages(Item $item)
    {
    return $this->collection($item->images, new ItemImageTransformer());
    }

    public function includeRoles(User $user)
    {
    return $this->collection($user->roles, new RoleTransformer());
    }
    }

    Usage from Controller (Single Item)

    $user = $this->getUser();

    $this->transform($user, UserTransformer::class);

    // more options are available

    Relationships (include)

    Loading relationships in Transformer (calling other Transformers):

    This can be done in 2 ways:

    1. By the User, he can specify what relations to return in response.

    2. By the Developer, define what relations to include at run time.

    From Front-end

    You can request data with their relationships directly from the API call using include=tags,user but first the Transformer need to have the availableIncludes defined with their functions like this:

    class AccountTransformer extends Transformer
    {
    protected $availableIncludes = [
    'tags',
    'user',
    ];

    public function transform(Account $account)
    {
    return [
    'id' => (int)$account->id,
    'url' => $account->url,
    'username' => $account->username,
    'secret' => $account->secret,
    'note' => $account->note,
    ];
    }

    public function includeTags(Account $account)
    {
    // use collection with `multi` relationship
    return $this->collection($account->tags, new TagTransformer());
    }

    public function includeUser(Account $account)
    {
    // use `item` with single relationship
    return $this->item($account->user, new UserTransformer());
    }
    }

    Now to get the Tags with the response when Accounts are requested pass the ?include=tags parameter with the [GET] request.

    To get Tags with User use the comma separator: ?include=tags,user.

    From Back-end

    From the controller you can dynamically set the DefaultInclude using (setDefaultIncludes) anytime you want.

    return $this->transform($rewards, ProductsTransformer::class)->setDefaultIncludes(['tags']);

    You need to have includeTags function defined on the transformer. Look at the full examples above.

    If you want to include a relation with every response from this transformer you can define the relation directly in the transformer on ($defaultIncludes)

    protected $availableIncludes = [
    'users',
    ];

    protected $defaultIncludes = [
    'tags',
    ];

    // ..

    You need to have includeUser and includeTags functions defined on the transformer. Look at the full examples above.

    Transformer Available helper functions:

    • user() : returns current authenticated user object.

    • ifAdmin($adminResponse, $clientResponse) : merges normal client response with the admin extra or modified results, when current authenticated user is Admin. Look at the full examples above.

    For more information about the Transformers read this.

    - + \ No newline at end of file diff --git a/docs/10.x/main-components/views/index.html b/docs/10.x/main-components/views/index.html index 5bd47cb61..0b72f64e0 100644 --- a/docs/10.x/main-components/views/index.html +++ b/docs/10.x/main-components/views/index.html @@ -4,13 +4,13 @@ Views | Apiato - +
    Version: 10.x

    Views

    Definition & Principles

    Read Porto SAP Documentation (#Views).

    Rules

    • Views SHOULD be created inside the Containers, and they will be automatically available for use in the Web Controllers.

    Folder Structure

     - app
    - Containers
    - {section-name}
    - {container-name}
    - UI
    - WEB
    - Views
    - welcome.php
    - profile.php
    - ...

    Code Sample

    Welcome page View

    <!DOCTYPE html>
    <html>
    <head>
    <title>Welcome</title>
    </head>
    <body>
    <div class="container">
    <div class="content">
    <div class="title">Welcome</div>
    </div>
    </div>
    </body>
    </html>

    Usage From Controller

    class Controller extends WebController
    {
    public function sayWelcome()
    {
    return view('just-welcome');
    }
    }

    Namespaces

    • By default, all Views are namespaced as the camelCase of its Section name + @ + camelCase of its Container name.

    For example, a view named welcome-page inside MySection > MyContainer can be accessed like this: view(mySection@myContainer::welcome-page)

    If you try to access it without the namespace view('just-welcome'), it will not find your View.

    note

    View files in Ship folder are exception to this and will be namespaced with the word "ship" instead of section name, e.g. view(ship::welcome-page)

    - + \ No newline at end of file diff --git a/docs/10.x/miscellaneous/tasks-queuing/index.html b/docs/10.x/miscellaneous/tasks-queuing/index.html index bbc80b10f..eae59616d 100644 --- a/docs/10.x/miscellaneous/tasks-queuing/index.html +++ b/docs/10.x/miscellaneous/tasks-queuing/index.html @@ -4,7 +4,7 @@ Tasks Queuing | Apiato - + @@ -18,7 +18,7 @@

    The only addition to the Laravel's queues in Apiato, is that by default, apiato detects which queue driver you are planning to use (based on the configs), to create the migration files required, in case type database is used.

    if (Config::get('queue.default') == 'database')
    {
    // do something
    }

    (refer to app/Ship/Migrations/ folder for more details).

    Beanstalkd

    In order to use Beanstalkd as your queue driver, you need to require the "pda/pheanstalk": "^4.0" package first. You can include this in any composer.json file you want.

    Further reading

    More info at Laravel Docs.

    - + \ No newline at end of file diff --git a/docs/10.x/miscellaneous/tasks-scheduling/index.html b/docs/10.x/miscellaneous/tasks-scheduling/index.html index 9cb2d0934..890e3d7f2 100644 --- a/docs/10.x/miscellaneous/tasks-scheduling/index.html +++ b/docs/10.x/miscellaneous/tasks-scheduling/index.html @@ -4,7 +4,7 @@ Tasks Scheduling | Apiato - + @@ -18,7 +18,7 @@ See the Commands Page.

    Once you have your command ready, go to app/Ship/Kernels/ConsoleKernel.php and start adding the commands you need to schedule inside the schedule function.

    Example:

    protected function schedule(Schedule $schedule)
    {
    $schedule->command('apiato:welcome')->everyMinute();
    $schedule->job(new myJob)->hourly();
    $schedule->exec('touch me.txt')->dailyAt('12:00');
    // ...
    }

    More details here.

    note

    You do not need to register the commands with the $commands property or point to them in the commands() function. Apiato will do that automatically for you.

    Further reading

    More info at Laravel Docs.

    - + \ No newline at end of file diff --git a/docs/10.x/miscellaneous/tests-helpers/index.html b/docs/10.x/miscellaneous/tests-helpers/index.html index 779019573..f3277dae2 100644 --- a/docs/10.x/miscellaneous/tests-helpers/index.html +++ b/docs/10.x/miscellaneous/tests-helpers/index.html @@ -4,7 +4,7 @@ Tests Helpers | Apiato - + @@ -24,7 +24,7 @@ testing data.

    1. Go to app/Ship/Seeder/SeedTestingData.php seeder class, and create your live testing data.

    2. Run this command php artisan apiato:seed-test

    Debugging with PsySH

    For better debugging and development, you can open a runtime developer console while executing your test.

    Using PsySH (interactive debugger and REPL "read-eval-print loop" for PHP). The package is required by the Laravel Tinker Package.

    To use it set the breakpoint eval(\Psy\sh()); anywhere you want in any Actions, Controllers, Tasks... and run your test normally.

    - + \ No newline at end of file diff --git a/docs/10.x/optional-components/commands/index.html b/docs/10.x/optional-components/commands/index.html index 6c8beea38..064dcf470 100644 --- a/docs/10.x/optional-components/commands/index.html +++ b/docs/10.x/optional-components/commands/index.html @@ -4,13 +4,13 @@ Commands | Apiato - +
    Version: 10.x

    Commands

    Definition

    • Commands are a Laravel artisan command. Laravel has its own default commands, and you can create your own as well.
    • Commands provide a way to interact with the Laravel app.
    • A Command can be scheduled by a Task scheduler, like Cron Job or by the Laravel built-in wrapper of the Cron Job "laravel scheduler".
    • Commands could be Closure based or Classes.
    • "dispatch" is the term that is usually used to call a Command.

    Principles

    • Containers MAY or MAY NOT have one or more Commands.

    • Every Command SHOULD call an Action to perform its job, and should not contain any business logic.

    • Ship may contain Application general Commands.

    Rules

    • All Commands MUST extend from App\Ship\Parents\Commands\ConsoleCommand.

    Folder Structure

    - app
    - Containers
    - {section-name}
    - {container-name}
    - UI
    - CLI
    - Commands
    - SayHelloCommand.php
    - ...
    - Ship
    - Commands
    - GeneralCommand.php
    - ...

    Code Samples

    A Simple Command

    class HelloWorldCommand extends ConsoleCommand
    {
    protected $signature = 'hello:world';
    protected $description = 'Hello World!';

    public function handle()
    {
    echo "Hello World :)\n";
    }
    }

    Usage from CLI (Terminal)

    php artisan hello:world

    Schedule Commands Execution

    To Schedule the execution of a Command checkout the Tasks Scheduling page.

    Define Consoles Routes

    To define Console route go to app/Ship/Commands/Routes.php.

    Further reading

    More info at Laravel Docs.

    - + \ No newline at end of file diff --git a/docs/10.x/optional-components/configs/index.html b/docs/10.x/optional-components/configs/index.html index d24b2ba31..8cf21b6b9 100644 --- a/docs/10.x/optional-components/configs/index.html +++ b/docs/10.x/optional-components/configs/index.html @@ -4,13 +4,13 @@ Configs | Apiato - +
    Version: 10.x

    Configs

    Definition

    Configs are files that contain configurations.

    In each Apiato container, there are two types of config files:

    • the container specific config file (a config file that contains the container specific configurations).
    • the container third party packages config files (a config file that belongs to a third party package, required by the composer file of the container).

    Principles

    • Your custom config files and third party packages config files, should be placed in the Container, unless it's too generic then it can be placed on the Ship Layer.
    • Containers can have as many config files as they need.

    Rules

    • When publishing a third party package config file, move it manually to its container or to the Ship Configs folder in case it is generic.
    • Framework config files (provided by Laravel) lives at the default config directory on the root of the project.
    • You SHOULD NOT add any config file to the root config directory.
    • The container specific config file, MUST be named this way:
      camelCase of its Section name + - + camelCase of its Container name, to prevent conflicts between third party packages and container specific packages.
      For example, config file inside MySection > MyContainer should be named like this: mySection-myContainer.php

    Folder Structure

    - app
    - Containers
    {section-name}
    - {container-name}
    - Configs
    - {section-name}-{container-name}.php
    - package-config-file1.php
    - ...
    - Ship
    - Configs
    - apiato.php
    - ...
    - config
    - app.php
    - ...

    Code Samples

    Example simple Config file

    // app/Containers/{SectionName}/{ContainerName}/Configs/{section-name}-{container-name}.php
    return [

    /*
    |--------------------------------------------------------------------------
    | Default Namespace
    |--------------------------------------------------------------------------
    */
    'namespace' => 'App',

    // some other config params here...

    You can access the respective configuration key like this:

    $value = Config::get('{section-name}-{container-name}.namespace');     // returns 'App'
    $value = config('{section-name}-{container-name}.namespace'); // same, but using laravel helper function
    Further reading

    More info at Laravel Docs.

    - + \ No newline at end of file diff --git a/docs/10.x/optional-components/criterias/index.html b/docs/10.x/optional-components/criterias/index.html index 4e67864c7..defe27f47 100644 --- a/docs/10.x/optional-components/criterias/index.html +++ b/docs/10.x/optional-components/criterias/index.html @@ -4,13 +4,13 @@ Criterias | Apiato - +
    Version: 10.x

    Criterias

    Definition

    Criterias are classes that hold and apply query condition when retrieving data from the database through a Repository.

    Without using a Criteria class, you can add your query conditions to a Repository or to a Model as scope, but with Criterias, your query conditions can be shared across multiple Models and Repositories. It allows you to define the query condition once and use it anywhere in the App.

    Principles

    • Every Container MAY have its own Criterias. However, shared Criterias SHOULD be created in the Ship layer.

    • A Criteria MUST not contain any extra code, if it needs data, the data SHOULD be passed to it from the Actions or the Task. It SHOULD not call any Task for data.

    Rules

    • All Criterias MUST extend from App\Ship\Parents\Criterias\Criteria.

    • Every Criteria SHOULD have an apply() function.

    Folder Structure

     - app
    - Containers
    - {section-name}
    - {container-name}
    - Data
    - Criterias
    - ColourRedCriteria.php
    - RaceCarsCriteria.php
    - ...
    - Ship
    - Criterias
    - CreatedTodayCriteria.php
    - NotNullCriteria.php
    - ...

    Code Samples

    A Shared Criteria

    class OrderByCreationDateDescendingCriteria extends Criteria
    {
    public function apply($model, PrettusRepositoryInterface $repository)
    {
    return $model->orderBy('created_at', 'desc');
    }
    }

    Usage from Task

    public function run()
    {
    $this->userRepository->pushCriteria(new OrderByCreationDateDescendingCriteria());
    return $this->userRepository->paginate();
    }

    Criteria Accepting Data Input

    class ThisUserCriteria extends Criteria
    {
    private $userId;

    public function __construct($userId)
    {
    $this->userId = $userId;
    }

    public function apply($model, PrettusRepositoryInterface $repository)
    {
    return $model->where('user_id', '=', $this->userId);
    }
    }

    Passing Data from Task to Criteria

    public function run($user)
    {
    $this->accountRepository->pushCriteria(new ThisUserCriteria($user->id));
    return $this->accountRepository->paginate();
    }

    Further reading

    More info at Laravel Docs.

    - + \ No newline at end of file diff --git a/docs/10.x/optional-components/events/index.html b/docs/10.x/optional-components/events/index.html index 92952523e..71fd59bce 100644 --- a/docs/10.x/optional-components/events/index.html +++ b/docs/10.x/optional-components/events/index.html @@ -4,13 +4,13 @@ Events | Apiato - +
    Version: 10.x

    Events

    Definition

    • Events provide a simple observer implementation, allowing you to subscribe and listen for various events that occur in your application.
    • Events are classes that can be fired from anywhere in your application.
    • An event class will usually be bound to one, or many Events Listeners Classes or has those Listeners registered to listen to it.
    • "fire" is the term that is usually used to call an Event.

    Principles

    • Events can be fired from Actions and or Tasks. It's preferable to choose one place only. (Tasks are recommended).
    • Events SHOULD be created inside the Containers. However, general Events CAN be created in the Ship layer.

    Rules

    • Event classes CAN be placed inside the Containers in Events folders or on the Ship for the general Events.
    • All Events MUST extend from App\Ship\Parents\Events\Event.

    Folder Structure

    - App
    - Containers
    - {section-name}
    - {container-name}
    - Events
    - SomethingHappenedEvent.php
    - ...
    - Listeners
    - ListenToMusicListener.php
    - ...

    - Ship
    - Events
    - GlobalStateChanged.php
    - SomethingBiiigHappenedEvent.php
    - ...

    Usage

    In Laravel, you can create and register events in multiple way. Read Laravel documentation to learn more about Events.

    Your custom EventServiceProvider needs to be registered in the containers MainServiceProvider as well.

    Broadcasting

    To define Broadcasting route go to app/Ship/Boardcasts/Routes.php.

    Further reading

    More info at Laravel Docs.

    - + \ No newline at end of file diff --git a/docs/10.x/optional-components/factories/index.html b/docs/10.x/optional-components/factories/index.html index 63492f83d..c8ffad2ac 100644 --- a/docs/10.x/optional-components/factories/index.html +++ b/docs/10.x/optional-components/factories/index.html @@ -4,13 +4,13 @@ Factories | Apiato - +
    Version: 10.x

    Factories

    Definition

    Factories (are a short name for Model Factories).

    Factories are used to generate some fake data with the help of Faker to be used for testing purposes.

    Factories are mainly used from Tests.

    Principles

    • Factories SHOULD be created in the Containers.

    Rules

    • All Factories MUST extend from App\Ship\Parents\Factories\Factory.

    Folder Structure

     - app
    - Containers
    - {section-name}
    - {container-name}
    - Data
    - Factories
    - UserFactory.php
    - ...

    Code Samples

    A User Model Factory

    class UserFactory extends Factory
    {
    protected $model = User::class;

    public function definition(): array
    {
    static $password;

    return [
    'name' => $this->faker->name,
    'email' => $this->faker->unique()->safeEmail,
    'password' => $password ?: $password = Hash::make('testing-password'),
    'email_verified_at' => now(),
    'remember_token' => Str::random(10),
    'is_admin' => false,
    ];
    }
    }

    Usage from Tests or Anywhere Else

    // creating 4 users
    User::factory()->count(4)->create();
    Further reading

    More info at Laravel Docs.

    - + \ No newline at end of file diff --git a/docs/10.x/optional-components/helpers/index.html b/docs/10.x/optional-components/helpers/index.html index 2d0fb5574..95bc347bb 100644 --- a/docs/10.x/optional-components/helpers/index.html +++ b/docs/10.x/optional-components/helpers/index.html @@ -4,13 +4,13 @@ Helpers | Apiato - +
    Version: 10.x

    Helpers

    Definition

    • Helpers are global PHP functions that you can call from anywhere in your application.
    • Helper files are simple PHP files that hold functions.

    Principles

    • Helpers SHOULD be created inside the Containers. However, general Helpers CAN be created in the Ship layer.
    • You can create as many helper files as you need, per container.
    • You can implement as many helper functions as you need, per helper file.
    • All Helper files will be autoloaded by the framework.

    Rules

    • Helpers CAN be placed inside the Containers in Helpers folder or on the Ship for the general Helpers.

    Folder Structure

    - App
    - Containers
    - {section-name}
    - {container-name}
    - Helpers
    - helpers.php
    - mix.php
    - ...

    - Ship
    - Helpers
    - helpers.php
    - mix.php
    - ...

    Usage

    if (!function_exists('add')) {
    function add(int $firstNumber, int $secondNumber): int
    {
    return $firstNumber + $secondNumber;
    }
    }
    - + \ No newline at end of file diff --git a/docs/10.x/optional-components/jobs/index.html b/docs/10.x/optional-components/jobs/index.html index af3dd668a..598153a7d 100644 --- a/docs/10.x/optional-components/jobs/index.html +++ b/docs/10.x/optional-components/jobs/index.html @@ -4,13 +4,13 @@ Jobs | Apiato - +
    Version: 10.x

    Jobs

    Definition

    • Jobs are simple classes that can do one thing or multiple related things.
    • Job is a name given to a class that is usually created to be queued (it's execution is usually deferred for later, after the execution of previous Jobs are completed).
    • Jobs can be scheduled to be executed later by a queuing mechanism (a queue system like beanstalkd).
    • When a Job class is dispatched, it performs its specific job and dies.
    • Laravel's queue worker will process every Job as it's pushed onto the queue.

    Principles

    • A Container MAY have more than one Job.

    Rules

    • All Jobs MUST extend from App\Ship\Parents\Jobs\Job.

    Folder Structure

    - app
    - Containers
    - {section-name}
    - {container-name}
    - Jobs
    - DoSomethingJob.php
    - DoSomethingElseJob.php

    Code Samples

    DemoJob

    class DemoJob extends Job
    {
    private $something;

    public function __construct(array $someData)
    {
    $this->something = $someData;
    }

    public function handle()
    {
    foreach ($this->something as $thing) {
    // do whatever you like
    }
    }
    }

    Check the parent Job class.

    Usage from Action

    // using helper function
    dispatch(new DemoJob($someData));

    // manually
    app(\Illuminate\Contracts\Bus\Dispatcher\Dispatcher::class)->dispatch(New DemoJob($someData));

    Execute Jobs Execution

    For running your Jobs checkout the Tasks Queuing page.

    Further reading

    More info at Laravel Docs.

    - + \ No newline at end of file diff --git a/docs/10.x/optional-components/languages/index.html b/docs/10.x/optional-components/languages/index.html index 7222e41b6..9c1397ab5 100644 --- a/docs/10.x/optional-components/languages/index.html +++ b/docs/10.x/optional-components/languages/index.html @@ -4,14 +4,14 @@ Languages | Apiato - +
    Version: 10.x

    Languages

    Definition

    Languages are not real Components, they are just files that holds translations.

    Rules

    • Languages CAN be placed inside the Containers. However, the default laravel resources/lang languages files are still loaded and can be used as well.

    • All Translations are namespaced as the camelCase of its Section name + @ + camelCase of its Container name.
      For example, translation key inside a translation file named messages inside MySection > MyContainer can be accessed like this: __(mySection@myContainer::messages.welcome)

    Folder Structure

    - app
    - Containers
    - {section-name}
    - {container-name}
    - Resources
    - Languages
    - en
    - messages.php
    - users.php
    - ar
    - messages.php
    - users.php

    Usage

    Nothing much to show here, here's how you use translated strings:

    __('mySection@myContainer::messages.welcome');
    Further reading

    More info at Localization.

    - + \ No newline at end of file diff --git a/docs/10.x/optional-components/mails/index.html b/docs/10.x/optional-components/mails/index.html index b728ef517..bbec7e13f 100644 --- a/docs/10.x/optional-components/mails/index.html +++ b/docs/10.x/optional-components/mails/index.html @@ -4,13 +4,13 @@ Mails | Apiato - +
    Version: 10.x

    Mails

    Definition

    The Mail component allows you to describe an email and send it whenever needed.

    Principles

    • Containers MAY or MAY NOT have one or more Mail.

    • Ship may contain general Mails.

    Rules

    • All Notifications MUST extend from App\Ship\Parents\Mails\Mail.
    • Email Templates must be placed inside the Mail directory in a Templates directory app/Containers/{section}/{container}/Mails/Templates.

    Folder Structure

    - app
    - Containers
    - {section-name}
    - {container-name}
    - Mails
    - UserRegisteredMail.php
    - ...
    - Templates
    - user-registered.blade.php
    - ...
    - Ship
    - Mails
    - SomeMail.php
    - ...
    - Templates
    - some-template.blade.php
    - ...

    Code Samples

    A simple Mail

    class UserRegisteredMail extends Mail implements ShouldQueue
    {
    use Queueable;

    protected $user;

    public function __construct(User $user)
    {
    $this->user = $user;
    }

    public function build()
    {
    return $this->view('appSection@user::user-registered')
    ->to($this->user->email, $this->user->name)
    ->with([
    'name' => $this->user->name,
    ]);
    }
    }

    Usage from an Action

    Notifications can be sent from Actions or Tasks using the Mail Facade.

    Mail::send(new UserRegisteredMail($user));

    Email Templates

    Templates should be placed inside a folder Templates inside the Mail folder.

    To access a Mail template (same like accessing a web view) you must call the camelCase of its Section name + @ + camelCase of its Container name.

    In the example below we're using the user-registered.blade.php template in the AppSection Section > User Container.

    $this->view('appSection@user::user-registered');

    Configure Emails

    Open the .env file and set the from mail and address. This will be used globally whenever the from function is not called in the Mail.

    MAIL_FROM_ADDRESS=test@test.test
    MAIL_FROM_NAME="apiato"

    To use different email address in some classes add ->to($this->email, $this->name) to the build function in your Mail class.

    By default Apiato is configured to use Log Driver MAIL_DRIVER=log, you can change that from the .env file.

    Queueing A Notification

    To queue a notification you should use Illuminate\Bus\Queueable and implement Illuminate\Contracts\Queue\ShouldQueue.

    Further reading

    More info at Laravel Docs.

    - + \ No newline at end of file diff --git a/docs/10.x/optional-components/middlewares/index.html b/docs/10.x/optional-components/middlewares/index.html index d480c7ec6..37e03c9a6 100644 --- a/docs/10.x/optional-components/middlewares/index.html +++ b/docs/10.x/optional-components/middlewares/index.html @@ -4,7 +4,7 @@ Middlewares | Apiato - + @@ -12,7 +12,7 @@
    Version: 10.x

    Middlewares

    Definition

    Middleware provide a convenient mechanism for filtering HTTP requests entering your application.

    You can enable and disable Middlewares as you wish.

    Principles

    • There are two types of Middlewares, General (applied on all the Routes by default) and Endpoints Middlewares (applied on some Endpoints).

    • The Middlewares CAN be placed in Ship layer or Container layer depending on its roles.

    Rules

    • If a Middleware is written inside a Container then it MUST be registered inside that Container.

    • To register Middlewares in a Container the container needs to have a MiddlewareServiceProvider, and like all other Container Providers it MUST be registered in the MainServiceProvider of that Container.

    • General Middlewares SHOULD live in the Ship layer app/Ship/Middlewares/* and are registered in the app/Ship/Kernels/HttpKernel.

    • Third Party packages Middleware CAN be registered in Containers or on the Ship layer (wherever they make more sense). For example the jwt.auth middleware "provided by the JWT package" should be registered in the Authentication Container (Containers/AppSection/Authentication/Providers/MiddlewareServiceProvider.php).

    Folder Structure

     - App
    - Containers
    - {section-name}
    - {container-name}
    - Middlewares
    - WebAuthentication.php
    - Ship
    - Middleware
    - Http
    - EncryptCookies.php
    - VerifyCsrfToken.php

    Code Sample

    Middleware Registration Inside the Container Example

    class MiddlewareServiceProvider extends MiddlewareProvider
    {
    protected array $middlewares = [
    // ..
    ];

    protected array $middlewareGroups = [
    'web' => [
    // ..
    ],
    'api' => [
    // ..
    ],
    ];

    protected array $routeMiddleware = [
    // apiato User Authentication middleware for Web Pages
    'guest' => RedirectIfAuthenticated::class
    ];
    }

    Middleware Registration Inside the Ship Layer (HTTP Kernel)

    class HttpKernel extends LaravelHttpKernel
    {
    /**
    * The application's global HTTP middleware stack.
    *
    * These middleware are run during every request to your application.
    *
    * @var array
    */
    protected $middleware = [
    // Laravel middleware's
    // \App\Http\Middleware\TrustHosts::class,
    TrustProxies::class,
    HandleCors::class,
    PreventRequestsDuringMaintenance::class,
    ValidatePostSize::class,
    TrimStrings::class,
    ConvertEmptyStringsToNull::class,
    ];

    /**
    * The application's route middleware groups.
    *
    * @var array
    */
    protected $middlewareGroups = [
    'web' => [
    EncryptCookies::class,
    AddQueuedCookiesToResponse::class,
    StartSession::class,
    // \Illuminate\Session\Middleware\AuthenticateSession::class,
    ShareErrorsFromSession::class,
    VerifyCsrfToken::class,
    SubstituteBindings::class,
    ],

    'api' => [
    // Note: The "throttle" Middleware is registered by the RoutesLoaderTrait in the Core
    SubstituteBindings::class,
    ValidateJsonContent::class,
    ProcessETagHeadersMiddleware::class,
    ProfilerMiddleware::class,
    ],
    ];

    /**
    * The application's route middleware.
    *
    * These middleware may be assigned to groups or used individually.
    *
    * @var array
    */
    protected $routeMiddleware = [
    'auth' => Authenticate::class,
    // 'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
    'cache.headers' => SetCacheHeaders::class,
    // Note: The "can" Middleware is registered by MiddlewareServiceProvider in Authorization Container
    // 'can' => \Illuminate\Auth\Middleware\Authorize::class,
    // Note: The "guest" Middleware is registered by MiddlewareServiceProvider in Authentication Container
    // 'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
    'password.confirm' => RequirePassword::class,
    'signed' => ValidateSignature::class,
    'throttle' => ThrottleRequests::class,
    'verified' => EnsureEmailIsVerified::class,
    ];

    /**
    * The priority-sorted list of middleware.
    *
    * Forces non-global middleware to always be in the given order.
    *
    * @var string[]
    */
    protected $middlewarePriority = [
    EncryptCookies::class,
    StartSession::class,
    ShareErrorsFromSession::class,
    Authenticate::class,
    ThrottleRequests::class,
    AuthenticateSession::class,
    SubstituteBindings::class,
    Authorize::class,
    ];
    }
    Further reading

    More info at Laravel Docs.

    - + \ No newline at end of file diff --git a/docs/10.x/optional-components/migrations/index.html b/docs/10.x/optional-components/migrations/index.html index be4b0e419..b11560316 100644 --- a/docs/10.x/optional-components/migrations/index.html +++ b/docs/10.x/optional-components/migrations/index.html @@ -4,13 +4,13 @@ Migrations | Apiato - +
    Version: 10.x

    Migrations

    Definition

    Migrations (are the short name for Database Migrations).

    Migrations are the version control of your database. They are very useful for generating and documenting the database tables.

    Principles

    • Migrations SHOULD be created inside the Containers folders.

    • Migrations will be autoloaded by the framework.

    Rules

    • No need to publish the DB Migrations. Just run the artisan migrate command and Laravel will read the Migrations from the Containers.

    Folder Structure

       - app
    - Containers
    - {section-name}
    - {container-name}
    - Data
    - Migrations
    - 2200_01_01_000001_create_something_table.php
    - ...

    Code Samples

    User CreateDemoTable Migrations

    class CreateDemoTable extends Migration
    {
    public function up()
    {
    Schema::create('demos', function (Blueprint $table) {
    $table->increments('id');
    // ...
    $table->timestamps();
    $table->softDeletes();
    });
    }

    public function down()
    {
    Schema::drop('demos');
    }
    }

    Further reading

    More info at Laravel Docs.

    - + \ No newline at end of file diff --git a/docs/10.x/optional-components/notifications/index.html b/docs/10.x/optional-components/notifications/index.html index 2c1cad29d..49d298900 100644 --- a/docs/10.x/optional-components/notifications/index.html +++ b/docs/10.x/optional-components/notifications/index.html @@ -4,7 +4,7 @@ Notifications | Apiato - + @@ -12,7 +12,7 @@
    Version: 10.x

    Notifications

    Definition

    Notifications allow you to inform the user about a state changes in your application.

    The Laravel notifications supports sending notifications across a variety of channels (mail, SMS, Slack, Database...).

    When using the Database channel, the notifications will be stored in a database to be displayed in your client interface.

    Principles

    • Containers MAY or MAY NOT have one or more Notification.

    • Ship MAY contain Application general Notifications.

    Rules

    • All Notifications MUST extend from App\Ship\Parents\Notifications\Notification.

    Folder Structure

    - app
    - Containers
    - {select-name}
    - {container-name}
    - Notifications
    - UserRegisteredNotification.php
    - ...
    - Ship
    - Notifications
    - SystemFailureNotification.php
    - ...

    Code Samples

    A Simple Notification

    class BirthdayReminderNotification extends Notification implements ShouldQueue
    {
    use Queueable;

    protected $notificationMessage;

    public function __construct($notificationMessage)
    {
    $this->notificationMessage = $notificationMessage;
    }

    public function toArray($notifiable)
    {
    return [
    'content' => $this->notificationMessage,
    ];
    }

    public function toMail($notifiable)
    {
    // $notifiable is the object you want to notify "e.g. user"
    return (new MailMessage)
    ->subject("Hello World")
    ->line("Hi, $notifiable->name")
    ->line($this->notificationMessage);
    }

    public function toSms($notifiable)
    {
    // ...
    }

    // ...
    }

    Usage from an Action or Task

    Notifications can be sent from Actions or Tasks using the Notification Facade.

    \Notification::send($user, new BirthdayReminderNotification($notificationMessage));

    Alternatively you can use the Illuminate\Notifications\Notifiable trait on the notifiable object "e.g. User" and then call it as follows:

    // call notify, found on the Notifiable trait
    $user->notify(new BirthdayReminderNotification($notificationMessage));

    Select Channels

    To select a notification channel, apiato have the app/Ship/Configs/notification.php config file where you can define the array of supported channels "e.g. SMS, Email, WebPush...", to be used for all your notifications.

    If you want to override the configuration for some notifications classes, or if you prefer to define the channels within each notification class itself, you can override the via function public function via($notifiable) in the notification class and define your channels.

    Checkout laravel notification channels for list of supported integrations.

    Queueing a Notification

    To queue a notification you should use Illuminate\Bus\Queueable and implement Illuminate\Contracts\Queue\ShouldQueue.

    Use DB channel

    Generally you need to generate the notification migration php artisan notifications:table, then run php artisan migrate, however just running the migration command will do the job, since Apiato already adds the _create_notifications_table.php in the default migrations files directory app/Ship/Migrations/.

    Further reading

    More info at Laravel Docs.

    - + \ No newline at end of file diff --git a/docs/10.x/optional-components/providers/index.html b/docs/10.x/optional-components/providers/index.html index dabdff998..76ebafaa7 100644 --- a/docs/10.x/optional-components/providers/index.html +++ b/docs/10.x/optional-components/providers/index.html @@ -4,7 +4,7 @@ Providers | Apiato - + @@ -14,7 +14,7 @@ In apiato those providers have been renamed and moved to the Ship Layer app/Ship/Parents/Providers/*:

    • AppServiceProvider
    • RouteServiceProvider
    • AuthServiceProvider
    • BroadcastServiceProvider
    • EventsServiceProvider
    note

    You should not touch those providers, instead you have to extend them from a containers providers in order to modify them. Example: the app/Containers/AppSection/Authentication/Providers/AuthProvider.php is extending the AuthServiceProvider to modify it.

    Those providers are not auto registered by default, thus writing any code there will not be available, unless you extend them. Once extended the child Provider should be registered in its Container Main Provider, which makes its parent available.

    This rule does not apply to the RouteServiceProvider since it's required by Apiato, this Provider is registered by the ShipProvider.

    Check How Service Providers are auto-loaded.

    Further reading

    More info at Laravel Docs.

    - + \ No newline at end of file diff --git a/docs/10.x/optional-components/repositories/index.html b/docs/10.x/optional-components/repositories/index.html index b9e625d5e..6b30afef1 100644 --- a/docs/10.x/optional-components/repositories/index.html +++ b/docs/10.x/optional-components/repositories/index.html @@ -4,13 +4,13 @@ Repositories | Apiato - +
    Version: 10.x

    Repositories

    Definition

    The Repository classes are an implementation of the Repository Design Pattern.

    Their major roles are separating the business logic from the data (or the data access Task).

    Repositories save and retrieves Models to/from the underlying storage mechanism.

    The Repository is used to separate the logic that retrieves the data and maps it to a Model, from the business logic that acts on the Model.

    Principles

    • Every Model SHOULD have a Repository.

    • A Model SHOULD always get accessed through its Repository. (Never accessed directly).

    Rules

    • All Repositories MUST extend from App\Ship\Parents\Repositories\Repository. Extending from this class will give you access to methods like (find, create, update and much more).

    • Repository name should be same as it's model name (model: Foo -> repository: FooRepository).

    • If a Repository belongs to a Model whose name is not equal to its Container name, then the Repository implement model() method like this.

    Folder Structure

     - app
    - Containers
    - {section-name}
    - {container-name}
    - Data
    - Repositories
    - UserRepository.php
    - ...

    Code Samples

    Demo Repository

    class DemoRepository extends Repository
    {
    protected $fieldSearchable = [
    'name' => 'like',
    'email' => '=',
    ];
    }

    Usage

    // paginate the data by 10
    $users = $userRepository->paginate(10);

    // search by 1 field
    $cars = $carRepository->findByField('colour', $colour);

    // searching multiple fields
    $offer = $offerRepository->findWhere([
    'offer_id' => $offer_id,
    'user_id' => $user_id,
    ])->first();

    //....

    Different Model and Container Name

    The model() method must be implemented when the model has different name than the container.

    class DemoRepository extends Repository
    {
    // ...

    public function model(): string
    {
    return Demo::class;
    }
    }

    Other Properties:

    API Query Parameters Property

    To enable query parameters (?search=text,...) in your API you need to set the property $fieldSearchable on the Repository class, to instruct the querying on your model. More details.

        protected $fieldSearchable = [
    'name' => 'like',
    'email' => '=',
    ];

    All other Properties

    Apiato uses the l5-repository package, to provide a lot of powerful features to the repository class.

    Further reading

    To learn more about all the properties you can use, visit the andersao/l5-repository package documentation.

    - + \ No newline at end of file diff --git a/docs/10.x/optional-components/seeders/index.html b/docs/10.x/optional-components/seeders/index.html index a63535990..c2aad4dc0 100644 --- a/docs/10.x/optional-components/seeders/index.html +++ b/docs/10.x/optional-components/seeders/index.html @@ -4,13 +4,13 @@ Seeders | Apiato - +
    Version: 10.x

    Seeders

    Definition

    Seeders (are a short name for Database Seeders).

    Seeders are classes made to seed the database with real data, this data usually should exist in the Application after the installation (Example: the default Users Roles and Permissions or the list of Countries).

    Principles

    • Seeders SHOULD be created in the Containers. (If the container is using a package that publishes a Seeder class, this class should be manually placed in the Container that make use of it. Do not rely on the package to place it in its right location).

    Rules

    • Seeders should be in the right directory inside the container to be loaded.

    • To avoid any conflict between containers seeders classes, you SHOULD always prepend the Seeders of each container with the container name. (Example: UserPermissionsSeeder, ItemPermissionsSeeder).

      note

      If 2 seeders classes have the same name but live in different containers, one of them will not be loaded. In these situations you can also prepend the seeder name with the section name

    • If you wish to order the seeding of the classes, you can just append _1, _2 to your classes.

    Folder Structure

     - App
    - Containers
    - {section-name}
    - {container-name}
    - Data
    - Seeders
    - ContainerNameRolesSeeder_1.php
    - ContainerNamePermissionsSeeder_2.php
    - ...

    Code Samples

    Demo Seeder

    class DemoSeeder_1 extends Seeder
    {
    public function run()
    {
    app(CreateRoleTask::class)->run('admin', 'Administrator', 'Administrator Role', 999);
    // ...
    }
    }
    note

    Same Seeder class is allowed to contain seeding for multiple Models.

    Run the Seeders

    After registering the Seeders you can run this command:

    php artisan db:seed

    Migrate & seed at the same time

    php artisan migrate --seed

    Testing Seeder Command

    It's useful sometimes to create a big set of testing data. apiato facilitates this task:

    1. Open app/Ship/Seeders/SeedTestingData.php and write your testing data here.
    2. Run this command any time you want this data available (example at staging servers):
    php artisan apiato:seed-test
    Further reading

    More info at Laravel Docs.

    - + \ No newline at end of file diff --git a/docs/10.x/optional-components/tests/index.html b/docs/10.x/optional-components/tests/index.html index 3b8eaf2ab..7453e7e9c 100644 --- a/docs/10.x/optional-components/tests/index.html +++ b/docs/10.x/optional-components/tests/index.html @@ -4,13 +4,13 @@ Tests | Apiato - +
    Version: 10.x

    Tests

    Definition

    Tests classes are created to test if the Application classes are working as expected.

    The two most essential Test types for this architecture are the Unit Tests and the Functional Tests. However, Integration and Acceptance Tests can be used as well.

    Principles

    • Containers MAY be covered by all types of Tests.

    • Use Functional Tests to test Container Routes are doing what's expected from them.

    • Use Unit Tests to test Container Actions and Tasks are doing what's expected from them.

    Rules

    • All Container Test classes SHOULD extend from a Container Internal TestCase class {container-name}/Tests/TestCase.php. The container TestCase MUST extend main TestCase on Ship layer App\Ship\Parents\Tests\PhpUnit\TestCase. (Adding functions to the container TestCase allows sharing those functions between all Test classes of the Container).

    Folder Structure

     - app
    - Containers
    - {section-name}
    - {container-name}
    - Tests
    - TestCase.php // the container test case
    - Unit
    - CreateUserTest.php
    - UpdateUserTest.php
    - ...
    - UI
    - API
    - Tests
    - Functional
    - LoginTest.php
    - LogoutTest.php
    - ...
    - WEB
    - Tests
    - Functional
    - LoginTest.php
    - LogoutTest.php
    - ...
    - CLI
    - Tests
    - Functional
    - BackupDataTest.php
    - ...

    Code Sample

    class DeleteUserTest extends TestCase
    {
    protected $endpoint = 'delete@v1/users/{id}';

    protected array $access = [
    'roles' => '',
    'permissions' => 'delete-users',
    ];

    public function testDeleteExistingUser()
    {
    $user = $this->getTestingUser();

    $response = $this->injectId($user->id)->makeCall();

    $response->assertStatus(204);
    }
    }

    See the Tests Helpers Page

    - + \ No newline at end of file diff --git a/docs/10.x/optional-components/values/index.html b/docs/10.x/optional-components/values/index.html index 5f5e40548..fc6e41ec0 100644 --- a/docs/10.x/optional-components/values/index.html +++ b/docs/10.x/optional-components/values/index.html @@ -4,7 +4,7 @@ Values | Apiato - + @@ -12,7 +12,7 @@
    Version: 10.x

    Values

    Definition & Principles

    Values are short names for the known "Value Objects" which are simple Objects, pretty similar to Models in the concept of representing data, but they do not get stored in the DB, thus they don't have ID's. They also do not hold functionality or change any state, they just hold data.

    A Value Object is an immutable object that is defined by its encapsulated attributes. We create Value Object when we need it to represent/serve/manipulate some data (attached as attributes), and we'll kill it later when we don't need it anymore, to recreate it again when needed.

    Rules

    • All Models MUST extend from App\Ship\Parents\Values\Value.

    Folder Structure

    - App
    - Containers
    - {section-name}
    - {container-name}
    - Values
    - Output.php
    - Region.php
    - ...

    Code Sample

    class Location extends Value
    {
    private $x = null;
    private $y = null;
    protected $resourceKey = 'locales';

    public function __construct($x, $y)
    {
    $this->x = $x;
    $this->y = $y;
    }

    public function getCoordinatesAsString()
    {
    return $this->x . ' - ' . $this->y;
    }
    }
    - + \ No newline at end of file diff --git a/docs/10.x/upgrade-guide/index.html b/docs/10.x/upgrade-guide/index.html index c66fa27e5..8f208e01e 100644 --- a/docs/10.x/upgrade-guide/index.html +++ b/docs/10.x/upgrade-guide/index.html @@ -4,7 +4,7 @@ Upgrade Guide | Apiato - + @@ -23,7 +23,7 @@ and the term New Project (referring to the new freshly installed Apiato 5.0).

    1) Download and install Apiato 5.0. See Application Setup.

    2) Delete the Containers directory app/Containers from the new project.

    3) Move the Containers directory app/Containers from the old project to the new project.

    4) Open this file app/Ship/composer.json in your old project and only copy the required dependencies, from the old project to the same file in the new project.

    5) Again, open the app/Ship/composer.json file in the new project, and remove the following dependencies: guzzlehttp/guzzle, prettus/l5-repository, barryvdh/laravel-cors, spatie/laravel-fractal, vinkla/hashids and johannesschobel/apiato-container-installer.

    6) Move and replace the following directories from the old project to the new project: config, public, resources, database and storage.

    7) Open config/app.php and replace App\Ship\Engine\Providers\PortoServiceProvider::class with Apiato\Core\Providers\ApiatoProvider::class.

    8) Move .gitignore, phpunit.xml and .env files, from the old project to the new project.

    9) Open the .env file on the new project and append this to it API_RATE_LIMIT_ENABLED=true.

    10) Open phpunit.xml file of the new project and delete this line from the file <file>./app/Ship/Engine/Loaders/FactoryMixer/FactoriesLoader.php</file>.

    11) If you had live testing data in your old project inside app/Ship/Seeders/Data/Testing/Seeders/TestingDataSeeder.php file, then copy that file content and past it in the new project inside app/Ship/Seeders/SeedTestingData.php. You will need to rename the class (not the file) from TestingDataSeeder to SeedTestingData, and you will need to update the namespace from namespace App\Ship\Seeders\Data\Testing\Seeders; to namespace App\Ship\Seeders;.

    12) If you ever used the HashIdTrait, you need to search and replace this namespace App\Ship\Engine\Traits\HashIdTrait with this Apiato\Core\Traits\HashIdTrait.

    13) Run composer update. If you got any error at this step, try to solve it or open an Issue.

    14) Move the .git directory from the old project to the new one. Add all changes git add . then commit git commit -m 'upgrade Apiato from 4.1 to 5.0'.

    15) Run your tests vendor/bin/phpunit.

    That's it :)

    How to manually upgrade older versions to 4.1?

    Use the Manual Upgrading Guide below.

    Manual Upgrading Guide

    These commands and examples, are compatible with the Apiato 8.0 upgrade. You can just copy/past.

    1) Checkout a new branch from your stable branch, to perform the upgrade.

    git checkout -b upgrade-apiato

    2) Configure a new remote (upstream) that points to the official Apiato repository.

    git remote add upstream https://github.com/apiato/apiato

    Verify the new upstream repository was added, by listing the current configured remote repositories.

    git remote -vv

    origin git@bitbucket.org:username/my-awesome-api.git (fetch)
    origin git@bitbucket.org:username/my-awesome-api.git (push)
    upstream git@github.com:apiato/apiato.git (fetch)
    upstream git@github.com:apiato/apiato.git (push)

    3) Checkout a new branch to hold the latest Apiato changes. This branch will be merged into your upgrade-apiato branch created above.

    git checkout -b apiato-{version}
    // Example: git checkout -b apiato-8.0

    4) Configure this branch to track an upstream specific branch.

    Replace {upstream-branch-name} with the branch name you want to upgrade to (for example 8.0).

    git fetch upstream {upstream-branch-name}
    // Example: git fetch upstream 8.0

    git branch --set-upstream-to upstream/{upstream-branch-name}
    // Example: git branch --set-upstream-to upstream/8.0

    Verify your local branch is tracking the Apiato specified upstream branch.

    git branch -vv

    apiato 77b4d945 [upstream/{upstream-branch-name}] ...
    master 77d302aa [origin/master] ...

    5) Make this branch identical to the remote upstream branch

    git reset --hard upstream/{upstream-branch-name}
    // Example: git reset --hard upstream/8.0

    Verify this branch now contains the latest changes from the upstream branch.

    git log

    6) Switch back to the upgrade-apiato branch

    git checkout upgrade-apiato

    7) Now lets merge the 2 branches. This step can be done in two ways:

    Option A: Merge all the changes together and solve the conflicts if any. (Recommended)

    You can execute the next command with different different parameters, below are 2 options to pick whatever feels safer to you. Do not execute both of them.

    A1: This will overwrite your changes with the upstream changes. (Try this first and if your tests failed then you can try the second one).

    git merge --allow-unrelated-histories --strategy-option=theirs apiato-{version}
    // Example: git merge --allow-unrelated-histories --strategy-option=theirs apiato-8.0

    A2: This will let you solve all the conflicts manually. (Can be the most secure choice, but it's time consuming as well.)

    git merge --allow-unrelated-histories apiato-{version}
    // Example: git merge --allow-unrelated-histories apiato-8.0

    Option B: Manually cherry pick the commits you likes to have:

    git log {upstream-branch-name}

    (copy each commit ID, one by one)

    git cherry-pick {commit-ID}

    (if you get any conflict solve it and keep moving)

    8) Compare your .env with the new .env-example and update it.

    9) Check everything is working. By running Composer install first then re-running your tests.

    • Read the changelog releases page.
    • You may want to update your custom containers dependencies, simply follow the composer install error outputs and bump each failing dependency. (Hint: visit each package releases page, and use the version which supports the supported version of Laravel).
    • You may need to fix the failing tests.
    composer install  &&  vendor/bin/phpunit

    10) Finally, merge the upgrade-apiato (which contains the upgraded changes) with your stable branch (could be master).

    git checkout master
    git merge upgrade-apiato

    php artisan -V

    Enjoy :)

    - + \ No newline at end of file diff --git a/docs/11.x/additional-features/documentation/index.html b/docs/11.x/additional-features/documentation/index.html index b77468914..f2f694d56 100644 --- a/docs/11.x/additional-features/documentation/index.html +++ b/docs/11.x/additional-features/documentation/index.html @@ -4,7 +4,7 @@ Documentation | Apiato - + @@ -15,7 +15,7 @@ access-private-docs-permission values in documentation config. By default, users need access-private-docs permission to access private docs.

    Edit Default Generated Values in Templates

    Apiato by defaults generates 2 API documentations, each one has its own apidoc.json file. Both can be modified from the Documentation Container in Containers/Vendor/Documentation/ApiDocJs/ and need Source code modification.

    Edit the Documentation Header

    The header is usually the Overview of your API. It contains Info about authenticating users, making requests, responses, potential errors, rate limiting, pagination, query parameters and anything you want.

    All this information is written in app/Containers/Vendor/Documentation/ApiDocJs/shared/header.template.md file, and the same file is used as header for both private and public documentations.

    To edit its content you need to modify its source code and open the markdown file in any markdown editor and edit it.

    You will notice some variables like {{rate-limit}} and {{token-expires}}. Those are replaced when running apiato:apidoc with real values from your application configuration files.

    Feel free to extend them to include more info about your API from the app/Containers/Vendor/Documentation/Tasks/RenderTemplatesTask.php class.

    Localization for Documentation Header

    Default, the documentation title is in English en localization.

    See which locales are supported by going in app/Containers/Vendor/Documentation/ApiDocJs/shared/

    There will be some header.template.{locale}.md files in the folder.

    You can change the language by adding APIDOC_LOCALE=ru to the .env file.

    If you didn't find a file with your locale, you can create it. You need to modify its source code and create new file like header.template.cn.md

    - + \ No newline at end of file diff --git a/docs/11.x/additional-features/localization/index.html b/docs/11.x/additional-features/localization/index.html index b54cfb4b3..e454dd81c 100644 --- a/docs/11.x/additional-features/localization/index.html +++ b/docs/11.x/additional-features/localization/index.html @@ -4,7 +4,7 @@ Localization | Apiato - + @@ -37,7 +37,7 @@ language in this specific language (e.g., locale_name => Deutsch). Furthermore, the language name is outputted in the applications default name (e.g., configured in app.locale). This would result in default_name => German.

    The same applies to the regions that are defined (e.g., de-DE). Consequently, this results in locale_name => Deutschland and default_name = Germany.

    Tests

    To change the default language in your tests requests. You can set the env language in the phpunit.xml file.

    - + \ No newline at end of file diff --git a/docs/11.x/additional-features/overview/index.html b/docs/11.x/additional-features/overview/index.html index d57b07a86..9709f2d2c 100644 --- a/docs/11.x/additional-features/overview/index.html +++ b/docs/11.x/additional-features/overview/index.html @@ -4,14 +4,14 @@ Overview | Apiato - +
    Version: 11.x

    Overview

    Apiato ships with a few pre-defined and pre-configured containers. Some of these containers (e.g. Documentation) are installed by default with a fresh Apiato project.

    - + \ No newline at end of file diff --git a/docs/11.x/additional-features/social-authentication/index.html b/docs/11.x/additional-features/social-authentication/index.html index dda9784bf..d32f2072d 100644 --- a/docs/11.x/additional-features/social-authentication/index.html +++ b/docs/11.x/additional-features/social-authentication/index.html @@ -4,7 +4,7 @@ Social Authentication | Apiato - + @@ -18,7 +18,7 @@ visit app/Containers/Vendor/Socialauth/UI/API/Routes/AuthenticateAll.v1.private.php.

  • The endpoint above should return the User and his Personal Access Token.

  • Example Google Response:

    {
    "data": {
    // user data
    .
    .
    .
    // additional social data if you have updated your transformer as mentioned above
    "social_auth_provider": "google",
    "social_id": "113834952367767922133",
    "social_avatar": {
    "avatar": "https:\/\/lh6.googleusercontent.com\/-OSItz6IHbSw\/AAA\/AMZuucltEs\/s96-c\/photo.jpg",
    "original": "https:\/\/lh6.googleusercontent.com\/-OSItz6IHbSw\/AAA\/AMZuucltEs\/s96-c\/photo.jpg"
    }
    },
    "meta": {
    "include": [
    "roles"
    ],
    "custom": {
    "token_type": "personal",
    "access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9...."
    }
    }
    }
    tip

    For testing purposes Apiato provides two web endpoints

    1. http://apiato.test/auth/{provider}/redirect which act as a client (step 3 above)
    2. http://apiato.test/auth/{provider}/callback which you can use in your provider's developer dashboard for callback url.
      Use those endpoints from your browser (replace the provider with any of the supported providers facebook, twitter,...) to get the oauth info and user data respectively.

    Social Authentication Container Customization

    You can customize this container by publishing its config and modifying its values

    php artisan vendor:publish

    Config file will be copied to app/Ship/Configs/vendor-socialAuth.php

    Support new Auth Provider

    1. Publish the configs
    2. Create your new auth provider by implementing App\Containers\Vendor\SocialAuth\Contracts\SocialAuthProvider interface.
      To get an idea about how to implement your own provider you can check out supported providers here App\Containers\Vendor\SocialAuth\SocialAuthProviders.
    3. Add your new provider to providers array in the vendor-socialAuth config.
        'providers' => [
    ...
    'something' => Location\Of\Your\Provider\SomthingSocialAuthProvider::class,
    ],

    Changing default used Repository, Transformer & DB user table name

    This container depends on Apiato's default user repository, transformer & database user table name. If you changed those defaults you can update and provide them in the configs.

    - + \ No newline at end of file diff --git a/docs/11.x/contribution-guide/index.html b/docs/11.x/contribution-guide/index.html index 8f21c4927..b72781130 100644 --- a/docs/11.x/contribution-guide/index.html +++ b/docs/11.x/contribution-guide/index.html @@ -4,7 +4,7 @@ Contribution Guide | Apiato - + @@ -42,7 +42,7 @@ 3 - Make sure you write a complete Changelog, in the release description. 4 - Change the default branch on GitHub to that new branch. 5 - If you updated the documentation, and you should! then visit the documentation repository and merge the PR into master.

    - + \ No newline at end of file diff --git a/docs/11.x/core-features/api-versioning/index.html b/docs/11.x/core-features/api-versioning/index.html index dc1edbf5a..0caf7bf06 100644 --- a/docs/11.x/core-features/api-versioning/index.html +++ b/docs/11.x/core-features/api-versioning/index.html @@ -4,13 +4,13 @@ API Versioning | Apiato - +
    Version: 11.x

    API Versioning

    Since Laravel does not support API versioning, Apiato provide a very easy way to implement versioning for your API.

    How it works

    Create:

    When creating a new API endpoint, specify the version number in the route file name following this naming format {endpoint-name}.{version-number}.{documentation-name}.php.

    Example:

    • MakeOrder.v1.public.php
    • MakeOrder.v2.public.php
    • ListOrders.v1.private.php

    Use:

    Automatically the endpoint inside that route file will be accessible by adding the version number to the URL.

    Example:

    • http://api.apiato.test/v1/register
    • http://api.apiato.test/v1/orders
    • http://api.apiato.test/v2/stores/123

    Version the API in header instead of URL

    First remove the URL version prefix:

    1. Edit app/Ship/Configs/apiato.php, set prefix to 'enable_version_prefix' => 'false',.
    2. Implement the Header versioning anyway you prefer. (this is not implemented in Apiato yet. Consider a contribution).
    - + \ No newline at end of file diff --git a/docs/11.x/core-features/authentication/index.html b/docs/11.x/core-features/authentication/index.html index 8cda5c435..f07ec70aa 100644 --- a/docs/11.x/core-features/authentication/index.html +++ b/docs/11.x/core-features/authentication/index.html @@ -4,7 +4,7 @@ Authentication | Apiato - + @@ -70,7 +70,7 @@ http://myapp.com/reset-password?email=mohammad.alavi1990@gmail.com&token=51f8d80182f3785648c9b9dc7162719d158fc418b3cca86c14963638ec83d663

    3) And when user click on that link it will go to your front end app reset password page. And then from there you should get the user's new password and call the /password-reset endpoint with all the required fields to reset the password.

    note

    You must set up the email to get this function to work, however for testing purposes set the MAIL_MAILER=log in your .env file in order to the see the email content in the log file storage/logs/laravel.log.

    Social Authentication

    For Social Authentication visit the Social Authentication page.

    - + \ No newline at end of file diff --git a/docs/11.x/core-features/authorization/index.html b/docs/11.x/core-features/authorization/index.html index 34a2cca6c..8e4c25763 100644 --- a/docs/11.x/core-features/authorization/index.html +++ b/docs/11.x/core-features/authorization/index.html @@ -4,13 +4,13 @@ Authorization | Apiato - +
    Version: 11.x

    Authorization

    Apiato provides a Role-Based Access Control (RBAC) through its Authorization Container.

    Behind the scenes apiato is using the Laravel's authorization functionality that was introduced in version 5.1.11 with the helper package laravel-permission. So you can always refer to the correspond documentation for more information.

    How it works

    Authorization in apiato is very simple and easy.

    1) Create some Roles and permissions. By default, an admin role and some permissions are provided by Apiato. You can find the code in app/Containers/AppSection/Authorization/Data/Seeders/* directory.

    2) Attach some permissions to the roles.

    3) Now start creating users (or use existing users), to assign them to the new created Roles.

    4) Finally, you need to protect your endpoints by Permissions (or/and Roles). The right place to do that is the Requests class.

    Example protecting the (delete user) endpoint with delete-users permission:

    class DeleteUserRequest extends Request
    {
    protected array $access = [
    'permissions' => 'delete-users',
    'roles' => '',
    ];

    public function authorize(): bool
    {
    return $this->check([
    'hasAccess',
    ]);
    }
    }

    For detailed explanation of this example, please visit the Requests Page.

    Responses

    Authorization failed JSON response:

    {
    "message": "This action is unauthorized."
    }

    Assign Roles & Permission to the Testing User

    You will need to set $access property in your test class, check out the Tests Helpers page for more details.

    Seeding some users (Admins)

    By default, Apiato comes with a Super Admin.

    This Super Admin Credentials are:

    This Admin seeded by app/Containers/Authorization/Data/Seeders/AuthorizationDefaultUsersSeeder_3.php.

    The Default Super User, has a default role admin.

    The admin default role has no permissions given to it.

    To give permissions to the admin role (or any other role), you can use the dedicated endpoints (from your custom Admin Interface).

    Checkout each container Seeders directory app/Containers/AppSection/{container-name}/Data/Seeders/, to edit the default Users, Roles and Permissions.

    Roles & Permissions guards

    By default, Apiato uses a single guard called web for all it's roles and permissions, you can add/edit this behavior and support multiple guards at any time. Refer to the laravel-permission package for more details.

    - + \ No newline at end of file diff --git a/docs/11.x/core-features/code-generator/index.html b/docs/11.x/core-features/code-generator/index.html index fb3707c88..2617c6e0d 100644 --- a/docs/11.x/core-features/code-generator/index.html +++ b/docs/11.x/core-features/code-generator/index.html @@ -4,7 +4,7 @@ Code Generator | Apiato - + @@ -17,7 +17,7 @@ the file and the folder structure needs to be the same as in vendor/apiato/core/Generator/Stubs.

    Say, if you like to change the action -> create.stub, simply copy the file to app/Ship/Generators/CustomStubs/actions/create.stub and start adapting it to your needs.

    If you run the respective command (e.g., in this case php artisan apiato:generate:action) and choose Create type this would read your specific create.stub file instead of the pre-defined one!

    Contributing

    If you would like to add your own generators, please check out the Contribution Guide.

    - + \ No newline at end of file diff --git a/docs/11.x/core-features/data-caching/index.html b/docs/11.x/core-features/data-caching/index.html index f4138a839..92c651e41 100644 --- a/docs/11.x/core-features/data-caching/index.html +++ b/docs/11.x/core-features/data-caching/index.html @@ -4,13 +4,13 @@ Data Caching | Apiato - +
    Version: 11.x

    Data Caching

    Enable / Disable Eloquent Query Caching

    info

    This feature is disabled By default.

    To enable it, go to app/Ship/Configs/repository.php config file and set cache > enabled => true, or set it from the .env file using ELOQUENT_QUERY_CACHE.

    More details can be found here.

    Users can skip the query caching and request new data by passing specific parameter to the Endpoint. Checkout its documentation here.

    Change different caching settings

    You can use different cache setting for each repository.

    To set cache settings on each repository, first the caching must be enabled, second you need to set some properties on the repository class to override the default values.

    For more details about all the properties refer to the L5 repository package documentation.

    Note: you don't need to use the CacheableRepository trait or implement the CacheableInterface since they both exist on the Abstract repository class (App\Ship\Parents\Repositories\Repository).

    - + \ No newline at end of file diff --git a/docs/11.x/core-features/default-endpoints/index.html b/docs/11.x/core-features/default-endpoints/index.html index 5800aa3dd..3ebb03a8b 100644 --- a/docs/11.x/core-features/default-endpoints/index.html +++ b/docs/11.x/core-features/default-endpoints/index.html @@ -4,13 +4,13 @@ Default Endpoints | Apiato - +
    Version: 11.x

    Default Endpoints

    Apiato comes loaded with many useful API endpoints for speeding up the development process.

    You can see the endpoints in three ways:

    • In Terminal, by running php artisan route:list -c.
    • In Browser, by generating the beautiful detailed documentation. See API Docs Generator.
    • In Code, by navigating to the Routes folder of each container's UI.
    - + \ No newline at end of file diff --git a/docs/11.x/core-features/etag/index.html b/docs/11.x/core-features/etag/index.html index f92c79468..c70e517e5 100644 --- a/docs/11.x/core-features/etag/index.html +++ b/docs/11.x/core-features/etag/index.html @@ -4,7 +4,7 @@ ETag | Apiato - + @@ -12,7 +12,7 @@
    Version: 11.x

    ETag

    ETag Middleware

    Apiato provides an ETag Middleware (ProcessETagHeadersMiddleware) that implements the Shallow technique. It can be used to reduce bandwidth on the client side (especially for Mobile devices).

    Enable / Disable ETag

    This feature is disabled By default. To enable it go to app/Ship/Configs/apiato.php and set use-etag to true. Of course your client should send the If-None-Match HTTP Header (= etag) in his request for this feature to work properly.

    - + \ No newline at end of file diff --git a/docs/11.x/core-features/hash-id/index.html b/docs/11.x/core-features/hash-id/index.html index 4ccf744b7..1a9323ba3 100644 --- a/docs/11.x/core-features/hash-id/index.html +++ b/docs/11.x/core-features/hash-id/index.html @@ -4,13 +4,13 @@ Hash ID | Apiato - +
    Version: 11.x

    Hash ID

    Hashing your internal ID's, is a very helpful feature for security reasons (to prevent some hack attacks) and business reasons (to hide the real total records from your competitors).

    Enable Hash ID

    Set the HASH_ID=true in the .env file.

    Also, with the feature make sure to always use the getHashedKey() on any model, whenever you need to return an ID (mainly from transformers) weather hashed ID or not.

    Example:


    'id' => $user->getHashedKey(),

    Note: if the feature is set to false HASH_ID=false the getHashedKey() will return the normal ID.

    Usage

    There are 2 ways an ID's can be passed to your system via the API:

    In URL example: www.apiato.test/items/abcdef.

    In parameters example: [GET] or [POST] www.apiato.test/items?id=abcdef.

    in both cases you will need to inform your API about what's coming form the Request class.

    Checkout the Requests page. After setting the $decode and $urlParameters properties on your Request class, the ID will be automatically decoded for you to apply validation rules on it or/and use it from your controller. ($request->id will return the decoded ID)

    Configuration

    You can change the default length and characters used in the ID from the config file app/Ship/Configs/hashids.phpor in the .env file by editing the HASH_ID_LENGTH value.

    You can set the HASH_ID_KEY in the .env file to any random string. You can generate this from any of the online random string generators, or run head /dev/urandom | tr -dc 'A-Za-z0-9!"#$%&'\''()*+,-./:;<=>?@[\]^_{|}~' | head -c 32 ; echo on the linux command-line. Apiato defaults to the APP_KEY should this not be set.

    The HASH_ID_KEY acts as the salt during hashing of the ID. This should never be changed in production as it renders all previously generated IDs impossible to decode.

    Testing

    In your tests you must hash the ID's before making the calls, because if you tell your Request class to decode an ID for you, it will throw an exception when the ID is not encoded.

    for Parameter ID's

    Always use getHashedKey() on your models when you want to get the ID

    Example:

    $data = [
    'roles_ids' => [
    $role1->getHashedKey(),
    $role2->getHashedKey(),
    ],
    'user_id' => $randomUser->getHashedKey(),
    ];
    $response = $this->makeCall($data);

    Or you can do this manually Hashids::encode($id);.

    for URL ID's

    You can use this helper function injectId($id, $skipEncoding = false, $replace = '{id}').

    Example:

    $response = $this->injectId($admin->id)->makeCall();

    More details on the Tests Helpers page.

    Availability

    You can use the Apiato\Core\Traits\HashIdTrait on any model or class, in order to have the encode and decode functions.

    By default, you have access to these functions $this->encode($id) and $this->decode($id) from all your Test classes and Controllers.

    - + \ No newline at end of file diff --git a/docs/11.x/core-features/pagination/index.html b/docs/11.x/core-features/pagination/index.html index 572fef03e..8bc8f0c62 100644 --- a/docs/11.x/core-features/pagination/index.html +++ b/docs/11.x/core-features/pagination/index.html @@ -4,7 +4,7 @@ Pagination | Apiato - + @@ -16,7 +16,7 @@ you can do it either project wide or per repository. After that a request can get all the data (with no pagination applied) by applying limit=0.

    This will return all matching entities:
    api.domain.test/endpoint?limit=0

    Project Wide

    Set PAGINATION_SKIP=true in .env file.

    Per Repository

    Override the $allowDisablePagination property in your specific Repository class.

    note

    Per repository configs override the global config and have precedence.

    - + \ No newline at end of file diff --git a/docs/11.x/core-features/profiler/index.html b/docs/11.x/core-features/profiler/index.html index 72eea91c5..b3c103a81 100644 --- a/docs/11.x/core-features/profiler/index.html +++ b/docs/11.x/core-features/profiler/index.html @@ -4,14 +4,14 @@ Profiler | Apiato - +
    Version: 11.x

    Profiler

    Profiling is very important to optimize the performance of your application, and help you better understand what happens when a request is received, as well as it can speed up the debugging process.

    Apiato uses the third-party package laravel-debugbar (which uses the PHP Debug Bar), to collect the profiling data.

    By default, the laravel-debugbar package displays the profiling data in the browser. However, Apiato uses a middleware (ProfilerMiddleware) to append the profiling data to the response.

    Sample Profiler response

    {
    // Actual Response Here...
    "_profiler": {
    "__meta": {
    "id": "X167f293230e3457f1bbd95d9c82aba4a",
    "datetime": "2017-09-22 18:45:27",
    "utime": 1506105927.799299,
    "method": "GET",
    "uri": "/",
    "ip": "172.20.0.1"
    },
    "messages": {
    "count": 0,
    "messages": []
    },
    "time": {
    "start": 1506105922.742068,
    "end": 1506105927.799333,
    "duration": 5.057265043258667,
    "duration_str": "5.06s",
    "measures": [
    {
    "label": "Booting",
    "start": 1506105922.742068,
    "relative_start": 0,
    "end": 1506105923.524004,
    "relative_end": 1506105923.524004,
    "duration": 0.7819359302520752,
    "duration_str": "781.94ms",
    "params": [],
    "collector": null
    },
    {
    "label": "Application",
    "start": 1506105923.535343,
    "relative_start": 0.7932748794555664,
    "end": 1506105927.799336,
    "relative_end": 0.00000286102294921875,
    "duration": 4.26399302482605,
    "duration_str": "4.26s",
    "params": [],
    "collector": null
    }
    ]
    },
    "memory": {
    "peak_usage": 13234248,
    "peak_usage_str": "12.62MB"
    },
    "exceptions": {
    "count": 0,
    "exceptions": []
    },
    "route": {
    "uri": "GET /",
    "middleware": "api, throttle:30,1",
    "domain": "http://api.apiato.test",
    "as": "apis_root_page",
    "controller": "App\\Containers\\Welcome\\UI\\API\\Controllers\\Controller@apiRoot",
    "namespace": "App\\Containers\\Welcome\\UI\\API\\Controllers",
    "prefix": "/",
    "where": [],
    "file": "app/Containers/Welcome/UI/API/Controllers/Controller.php:20-25"
    },
    "queries": {
    "nb_statements": 0,
    "nb_failed_statements": 0,
    "accumulated_duration": 0,
    "accumulated_duration_str": "0μs",
    "statements": []
    },
    "swiftmailer_mails": {
    "count": 0,
    "mails": []
    },
    "logs": {
    "count": 3,
    "messages": [
    {
    "message": "...",
    "message_html": null,
    "is_string": false,
    "label": "error",
    "time": 1506105927.694807
    },
    {
    "message": "...",
    "message_html": null,
    "is_string": false,
    "label": "error",
    "time": 1506105927.694811
    },
    {
    "message": "[2017-09-18 17:38:15] testing.INFO: New User registration. ID = 970ylqvaogmxnbdr | Email = apiato@mail.test. Thank you for signing up.\n</div>\n</body>\n</html>\n \n",
    "message_html": null,
    "is_string": false,
    "label": "info",
    "time": 1506105927.694812
    }
    ]
    },
    "auth": {
    "guards": {
    "web": "array:2 [\n \"name\" => \"Guest\"\n \"user\" => array:1 [\n \"guest\" => true\n ]\n]",
    "api": "array:2 [\n \"name\" => \"Guest\"\n \"user\" => array:1 [\n \"guest\" => true\n ]\n]"
    },
    "names": ""
    },
    "gate": {
    "count": 0,
    "messages": []
    }
    }
    }

    Configuration

    By default, the profiler feature is turned off. To turn it on edit the .env file and set DEBUGBAR_ENABLED=true.

    To control and modify the profiler response, you need to edit this config file app/Ship/Configs/debugbar.php.

    - + \ No newline at end of file diff --git a/docs/11.x/core-features/query-parameters/index.html b/docs/11.x/core-features/query-parameters/index.html index b520b04cc..ee4688cde 100644 --- a/docs/11.x/core-features/query-parameters/index.html +++ b/docs/11.x/core-features/query-parameters/index.html @@ -4,7 +4,7 @@ Query Parameters | Apiato - + @@ -25,7 +25,7 @@ accepts driver as relationship ($availableIncludes in Transformer).

    Nested Includes

    It is also possible to request "nested includes". Extend the example from above. Imagine, that a Driver may also have a relationship to an Address object. You can access this information as well by calling ?include=driver,driver.address.

    Of course, the address include is defined in the respective DriverTransformer that is used here.

    Where to define the includes:

    Every Transformer can have 2 types of includes $availableIncludes and $defaultIncludes:

        protected $availableIncludes = [
    'products',
    'store',
    'recipients',
    ];

    protected $defaultIncludes = [
    'invoice',
    ];

    $defaultIncludes will not be listed in the response, only the $availableIncludes will be.

    Visit the Transformers page for more details.

    Skip caching

    (provided by the L5 Repository)

    Note: You need to turn the Eloquent Query Caching ON for this feature to work. ELOQUENT_QUERY_CACHE=true in .env.

    To run a new query and force disabling the cache on certain endpoints, you can use this parameter

    ?skipCache=true

    It's not recommended to keep skipping cache as it has bad impact on the performance.

    Configuration

    Most of these parameters are provided by the L5 Repository and configurable from the Ship/Configs/repository.php file. Some of them are built in house, or inherited from other packages such as Fractal.

    See the Query parameters from the User Developer perspective

    1) Generate the Default API documentation

    2) Visit the documentation URL

    More details in the API Docs Generator page.

    More Information

    For more details on these parameters check out these links:

    - + \ No newline at end of file diff --git a/docs/11.x/core-features/rate-limiting/index.html b/docs/11.x/core-features/rate-limiting/index.html index 15225b2bf..2757ac313 100644 --- a/docs/11.x/core-features/rate-limiting/index.html +++ b/docs/11.x/core-features/rate-limiting/index.html @@ -4,14 +4,14 @@ Rate Limiting | Apiato - +
    Version: 11.x

    Rate Limiting

    Apiato uses the default Laravel middleware for rate limiting (throttling).

    All REST API requests are throttled to prevent abuse and ensure stability. The exact number of calls that your application can make per day varies based on the type of request you are making.

    The rate limit window is 1 minute per endpoint, with most individual calls allowing for 30 requests in each window.

    In other words, each user is allowed to make 30 calls per endpoint every 1 minute. (For each unique access token).

    To update these values go to app/Ship/Configs/apiato.php config file, or to the ENV file.

    'throttle' => [
    'enabled' => env('GLOBAL_API_RATE_LIMIT_ENABLED', true),
    'attempts' => env('GLOBAL_API_RATE_LIMIT_ATTEMPTS_PER_MIN', '30'),
    'expires' => env('GLOBAL_API_RATE_LIMIT_EXPIRES_IN_MIN', '1'),
    ]
    GLOBAL_API_RATE_LIMIT_ENABLED=true
    GLOBAL_API_RATE_LIMIT_ATTEMPTS_PER_MIN=30
    GLOBAL_API_RATE_LIMIT_EXPIRES_IN_MIN=1

    For how many hits you can preform on an endpoint, you can always check the header:

    X-RateLimit-Limit →30
    X-RateLimit-Remaining →29

    Enable/Disable Rate Limiting:

    The global API rate limiting middleware name is api and is enabled and applied to all the Container API Endpoints by default.

    Disable on specific endpoint:

    This middleware can be bypassed using withoutMiddleware() method on a specific route.

    Disable on all endpoints (globally):

    To disable it set GLOBAL_API_RATE_LIMIT_ENABLED to false in the .env file.

    - + \ No newline at end of file diff --git a/docs/11.x/core-features/useful-commands/index.html b/docs/11.x/core-features/useful-commands/index.html index b01d2ad14..87f038ee8 100644 --- a/docs/11.x/core-features/useful-commands/index.html +++ b/docs/11.x/core-features/useful-commands/index.html @@ -4,14 +4,14 @@ Useful Commands | Apiato - +
    Version: 11.x

    Useful Commands

    Apiato is loaded with many useful commands to help you speed up the development process. You can see list of all commands, by typing php artisan and look for Apiato section.

    Available Commands

    • php artisan apiato Display the current Apiato version.
    • php artisan apiato:apidoc Generate API Documentations with apidoc from your routes Docblock. More details.
    • php artisan apiato:create:admin Create a new User with the ADMIN role
    • php artisan apiato:generate:{component} Generate a specific component for the framework (e.g., Action, Task, ...). For more details on the Code Generator click here.
    • php artisan apiato:list:actions List all Actions in the Application.
    • php artisan apiato:list:tasks List all Tasks in the Application.
    • php artisan apiato:seed-deploy Seeds your custom deployment data from app/Ship/Seeders/SeedDeploymentData.php.
    • php artisan apiato:seed-test Seeds your custom testing data from app/Ship/Seeders/SeedTestingData.php.
    • php artisan apiato:welcome Just saying welcome from a container.
    - + \ No newline at end of file diff --git a/docs/11.x/core-features/user-registration/index.html b/docs/11.x/core-features/user-registration/index.html index 40299ffdf..bd0b24a97 100644 --- a/docs/11.x/core-features/user-registration/index.html +++ b/docs/11.x/core-features/user-registration/index.html @@ -4,13 +4,13 @@ User Registration | Apiato - +
    Version: 11.x

    User Registration

    Register users by credentials (email and passwords)

    Call the http://api.apiato.test/v1/register endpoint (you can find its documentation after generating the API Docs.

    Check out the registerUser endpoint in the API Routes files.

    This will register a new User and respond with user object.

    Registration request:

    curl --request POST \
    --url http://api.apiato.test/v1/register \
    --header 'accept: application/json' \
    --header 'content-type: application/x-www-form-urlencoded' \
    --data 'email=john%40doe.com&password=password&name=John%20Doe'

    Registration response:

    {
    "data": {
    "object": "User",
    "id": "XbPW7awNkzl83LD6",
    "name": "John Doe",
    "email": "john@doe.com",
    "email_verified_at": null,
    "gender": null,
    "birth": null,
    "created_at": "2021-04-15T14:17:24.000000Z",
    "updated_at": "2021-04-15T14:17:24.000000Z",
    "readable_created_at": "1 second ago",
    "readable_updated_at": "1 second ago"
    },
    "meta": {
    "include": [
    "roles"
    ],
    "custom": []
    }
    }

    Note: After registration in order to get the user access token you will have to send another call to http://api.example.com/v1/oauth/token with following fields and values

    username => your_username e.g. admin@admin.com
    password => your_password
    grant_type => password
    client_id => your_client_id
    client_secret => your_client_secret

    For third-party clients you must have client ID and secret first. You can generate them by creating new client in your app using Laravel Passport.

    For first-party clients you can use a proxy to add those fields on requests coming from your trusted client. For an example on how to do it look at ProxyLoginForWebClientAction Action in Authentication Container.

    Register users by Social Account

    (Facebook, Twitter, Google..)

    Checkout the Social Authentication Page for how to Sign up with Social Account.

    - + \ No newline at end of file diff --git a/docs/11.x/core-features/validation/index.html b/docs/11.x/core-features/validation/index.html index e92faf14a..ee048ee6c 100644 --- a/docs/11.x/core-features/validation/index.html +++ b/docs/11.x/core-features/validation/index.html @@ -4,13 +4,13 @@ Validation | Apiato - +
    Version: 11.x

    Validation

    Apiato uses the powerful Laravel validation system.

    In Apiato, validation must be defined in Request component, since every request might have different rules.

    Validation rules are automatically applied, once injecting the Request in the Controller.

    Requests help validating User data, accessibility, ownership and more.

    Example Request with Validation rules:

    namespace App\Containers\AppSection\User\UI\API\Requests;

    use App\Ship\Parents\Requests\Request;

    class RegisterUserRequest extends Request
    {
    /**
    * @return array
    */
    public function rules()
    {
    return [
    'email' => 'required|email|max:200|unique:users,email',
    'password' => 'required|min:20|max:300',
    'name' => 'required|min:2|max:400',
    ];
    }

    }

    Usage from Controller Example:

        public function registerUser(RegisterUserRequest $request)
    {
    $user = app(RegisterUserAction::class)->run($request);
    return $this->transform($user, UserTransformer::class);
    }

    Responses

    Validation Error response format:

    Single Field:

    {
    "message": "The given data was invalid.",
    "errors": {
    "email": [
    "The email has already been taken."
    ]
    }
    }

    Multiple Fields:

    {
    "message": "The given data was invalid.",
    "errors": {
    "email": [
    "The email has already been taken."
    ],
    "password": [
    "The password field is required."
    ]
    }
    }

    More details about requests in the Requests Page.

    - + \ No newline at end of file diff --git a/docs/11.x/faq/index.html b/docs/11.x/faq/index.html index f5c646387..b7a725793 100644 --- a/docs/11.x/faq/index.html +++ b/docs/11.x/faq/index.html @@ -4,7 +4,7 @@ Frequently Asked Questions | Apiato - + @@ -37,7 +37,7 @@ Discord.

    Lastly, if you got your question answered, consider sharing it, if you believe it can help others. You can submit a PR adding the questions and answer here on the FAQ page. Or leave it somewhere on the repository or on the chat room. Thanks in advance :)

    - + \ No newline at end of file diff --git a/docs/11.x/getting-started/container-installer/index.html b/docs/11.x/getting-started/container-installer/index.html index 6a2db4590..aae3cbaf7 100644 --- a/docs/11.x/getting-started/container-installer/index.html +++ b/docs/11.x/getting-started/container-installer/index.html @@ -4,7 +4,7 @@ Container Installer | Apiato - + @@ -20,7 +20,7 @@ that allows installing/updating containers.
  • You must provide the key extra.apiato.container.name. This key indicates the name of the folder (e.g., container) when installing the package to the /app/Containers/Vendor folder. In the shown example, the container would be installed to app/Containers/Vendor/Foo.
  • - + \ No newline at end of file diff --git a/docs/11.x/getting-started/conventions-and-principles/index.html b/docs/11.x/getting-started/conventions-and-principles/index.html index fafd589b1..2677cc51f 100644 --- a/docs/11.x/getting-started/conventions-and-principles/index.html +++ b/docs/11.x/getting-started/conventions-and-principles/index.html @@ -4,13 +4,13 @@ Conventions | Apiato - +
    Version: 11.x

    Conventions

    HTTP Methods usage in RESTful API's

    • GET (SELECT): retrieve a specific resource from the server, or a listing of resources.
    • POST (CREATE): create a new resource on the server.
    • PUT (UPDATE): update a resource on the server, providing the entire resource.
    • PATCH (UPDATE): update a resource on the server, providing only changed attributes.
    • DELETE (DELETE): remove a resource from the server.

    Naming Conventions for Routes & Actions

    • GetAllResource: to fetch all resources.
    • FindResourceByID: to search for single resource by its unique identifier.
    • CreateResource: to create a new resource.
    • UpdateResource: to update/edit existing resource.
    • DeleteResource: to delete a resource.

    General guidelines and principles for RESTful URLs

    • A URL identifies a resource.
    • URLs should include nouns, not verbs.
    • Use plural nouns only for consistency (no singular nouns).
    • Use HTTP verbs (GET, POST, PUT, DELETE) to operate on the collections and elements.
    • You should not need to go deeper than resource/identifier/resource.
    • Put the version number at the base of your URL, for example http://apiato.test/v1/path/to/resource.
    • If an input data changes the logic of the endpoint, it should be passed in the URL. If not can go in the header "like Auth Token".
    • Don't use query parameters to alter state.
    • Don't use mixed-case paths if you can help it; lowercase is best.
    • Don't use implementation-specific extensions in your URIs (.php, .py, .pl, etc.)
    • Limit your URI space as much as possible. And keep path segments short.
    • Don't put metadata in the body of a response that should be in a header

    Good URL examples

    • Find a single Car by its unique identifier (ID):
      • GET http://www.api.apiato.test/v1/cars/123
    • Get all Cars:
      • GET http://www.api.apiato.test/v1/cars
    • Find/Search cars by one or more fields:
      • GET http://www.api.apiato.test/v1/cars?search=maker:mercedes
      • GET http://www.api.apiato.test/v1/cars?search=maker:mercedes;color:white
    • Order and Sort query result:
      • GET http://www.api.apiato.test/v1/cars?orderBy=created_at&sortedBy=desc
      • GET http://www.api.apiato.test/v1/cars?search=maker:mercedes&orderBy=created_at&sortedBy=desc
    • Specify optional fields:
      • GET http://www.api.apiato.test/v1/cars?filter=id;name;status
      • GET http://www.api.apiato.test/v1/cars/123?filter=id;name;status
    • Get all Drivers belonging to a Car:
      • GET http://www.api.apiato.test/v1/cars/123/drivers
      • GET http://www.api.apiato.test/v1/cars/123/drivers/123/addresses
    • Include Drivers objects relationship with the car response:
      • GET http://www.api.apiato.test/v1/cars/123?include=drivers
      • GET http://www.api.apiato.test/v1/cars/123?include=drivers,owner
    • Add new Car:
      • POST http://www.api.apiato.test/v1/cars
    • Add new Driver to a Car:
      • POST http://www.api.apiato.test/v1/cars/123/drivers

    General principles for HTTP methods

    • Don't ever use GET to alter state; to prevent Googlebot from corrupting your data. And use GET as much as possible.
    • Don't use PUT unless you are updating an entire resource. And unless you can also legitimately do a GET on the same URI.
    • Don't use POST to retrieve information that is long-lived or that might be reasonable to cache.
    • Don't perform an operation that is not idempotent with PUT.
    • Use GET for things like calculations, unless your input is large, in which case use POST.
    • Use POST in preference to PUT when in doubt.
    • Use POST whenever you have to do something that feels RPC-like.
    • Use PUT for classes of resources that are larger or hierarchical.
    • Use DELETE in preference to POST to remove resources.
    - + \ No newline at end of file diff --git a/docs/11.x/getting-started/installation/index.html b/docs/11.x/getting-started/installation/index.html index 3b49badfc..e404a5b66 100644 --- a/docs/11.x/getting-started/installation/index.html +++ b/docs/11.x/getting-started/installation/index.html @@ -4,7 +4,7 @@ Installation | Apiato - + @@ -28,7 +28,7 @@ try running this command homestead halt && homestead up --provision.

    Using anything else

    If you're not into virtualization solutions, you can set up your environment directly on your machine. Check the software's requirements list.

    Let's Play

    Now let's see it in action

    Open your web browser and visit:

    • http://apiato.test You should see an HTML page, with Apiato in the middle.
    • http://api.apiato.test You should see a response like this:
    [
    "Welcome to Apiato"
    ]

    Open your HTTP client and call:

    • http://api.apiato.test/ You should see a JSON response with message: "Welcome to apiato.",
    • http://api.apiato.test/v1 You should see a JSON response with message: "Welcome to apiato (API V1).",

    Make some HTTP calls to the API:

    To make the calls you can use Postman, HTTPIE or any other tool you prefer.

    Let's test the (user registration) endpoint http://api.apiato.test/v1/register with cURL:

    curl -X POST -H "Accept: application/json" -H "Cache-Control: no-cache" -F "email=John@Doe.me" -F "password=so-secret" -F "name=John Doe" "http://api.apiato.test/v1/register"

    You should get a response like this:

    Header:

    Access-Control-Allow-Origin → ...
    Cache-Control → ...
    Connection → keep-alive
    Content-Language → en
    Content-Type → application/json
    Date → Wed, 11 Apr 2000 22:55:88 GMT
    Server → nginx
    Transfer-Encoding → chunked
    Vary → Origin
    X-Powered-By → PHP/7.7.7
    X-RateLimit-Limit → 30
    X-RateLimit-Remaining → 29

    Body:

    {
    "data": {
    "object": "User",
    "id": "7VgmkMw7rR2pWO5j",
    "name": "John Doe",
    "email": "John@Doe.me",
    "email_verified_at": null,
    "gender": null,
    "birth": null,
    "created_at": "2021-04-12T13:33:24.000000Z",
    "updated_at": "2021-04-12T13:33:24.000000Z",
    "readable_created_at": "1 second ago",
    "readable_updated_at": "1 second ago"
    },
    "meta": {
    "include": [
    "roles"
    ],
    "custom": []
    }
    }
    - + \ No newline at end of file diff --git a/docs/11.x/getting-started/markdown-features/index.html b/docs/11.x/getting-started/markdown-features/index.html index e167fd59c..df534a980 100644 --- a/docs/11.x/getting-started/markdown-features/index.html +++ b/docs/11.x/getting-started/markdown-features/index.html @@ -4,13 +4,13 @@ Markdown Features | Apiato - +
    Version: 11.x

    Markdown Features

    Docusaurus supports the Markdown syntax and has some additional features.

    Front Matter

    Markdown documents can have associated metadata at the top called Front Matter:

    ---
    id: my-doc
    title: My document title
    description: My document description
    sidebar_label: My doc
    ---

    Markdown content

    Regular Markdown links are supported using url paths or relative file paths.

    Let's see how to [Create a page].
    Let's see how to [Create a page].

    Let's see how to [Create a page].

    Markdown images

    Regular Markdown images are supported.

    Add an image at static/img/logo.png and use this Markdown declaration:

    ![Docusaurus logo](/img/logo.png)

    Docusaurus logo

    Code Blocks

    Markdown code blocks are supported with Syntax highlighting.

    ```jsx title="src/components/HelloDocusaurus.js"
    function HelloDocusaurus() {
    return (
    <h1>Hello, Docusaurus!</h1>
    )
    }
    ```
    src/components/HelloDocusaurus.js
    function HelloDocusaurus() {
    return <h1>Hello, Docusaurus!</h1>;
    }

    Admonitions

    Docusaurus has a special syntax to create admonitions and callouts:

    :::tip My tip

    Use this awesome feature option

    :::

    :::danger Take care

    This action is dangerous

    :::
    My tip

    Use this awesome feature option

    Take care

    This action is dangerous

    React components

    Thanks to MDX, you can make your doc more interactive and use React components inside Markdown:

    export const Highlight = ({children, color}) => (
    <span
    style={{
    backgroundColor: color,
    borderRadius: '2px',
    color: 'red',
    padding: '0.2rem',
    }}>
    {children}
    </span>
    );

    <Highlight color="#25c2a0">Docusaurus green</Highlight> and <Highlight color="#1877F2">Facebook blue</Highlight> are my favorite colors.
    Docusaurus green and Facebook blue are my favorite colors.
    - + \ No newline at end of file diff --git a/docs/11.x/getting-started/requests/index.html b/docs/11.x/getting-started/requests/index.html index b5a6c8832..cbc46655d 100644 --- a/docs/11.x/getting-started/requests/index.html +++ b/docs/11.x/getting-started/requests/index.html @@ -4,7 +4,7 @@ Requests | Apiato - + @@ -17,7 +17,7 @@ you can force your users to send application/json by setting 'force-accept-header' => true, in app/Ship/Configs/apiato.php or allow them to skip it completely by setting the 'force-accept-header' => false,. By default this flag is set to false.

    Calling Endpoints

    Calling unprotected endpoint example:

    curl -X POST -H "Accept: application/json" -H "Content-Type: application/x-www-form-urlencoded; -F "email=admin@admin.com" -F "password=admin" -F "=" "http://api.domain.test/v2/register"

    Calling protected endpoint (passing Bearer Token) example:

    curl -X GET -H "Accept: application/json" -H "Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9..." -H "http://api.domain.test/v1/users"
    - + \ No newline at end of file diff --git a/docs/11.x/getting-started/responses/index.html b/docs/11.x/getting-started/responses/index.html index 1a5385ee8..9714c99d9 100644 --- a/docs/11.x/getting-started/responses/index.html +++ b/docs/11.x/getting-started/responses/index.html @@ -4,7 +4,7 @@ Responses | Apiato - + @@ -17,7 +17,7 @@ If no $resourceKey is defined at the Model, the ShortClassName is used as key. For example, the ShortClassName of the App\Containers\AppSection\User\Models\User::class is User.

    Error Responses formats

    Visit each feature, e.g. the Authentication and there you will see how an unauthenticated response looks like, same for Authorization, Validation and so on.

    Building a Responses from the Controller:

    Checkout the Controller response builder helper functions.

    - + \ No newline at end of file diff --git a/docs/11.x/getting-started/samples/index.html b/docs/11.x/getting-started/samples/index.html index d11182452..6494a694b 100644 --- a/docs/11.x/getting-started/samples/index.html +++ b/docs/11.x/getting-started/samples/index.html @@ -4,7 +4,7 @@ Samples | Apiato - + @@ -12,7 +12,7 @@
    Version: 11.x

    Samples

    The basic flow

    When an HTTP request is received, it first hits your predefined Endpoint (each endpoint live in its own Route file).

    Sample Route Endpoint

    Route::get('/hello', [Controller::class, 'sayHello']);

    After the user makes a request to the endpoint [GET] www.api.apiato.com/v1/hello it calls the defined controller function (sayHello).

    Sample Controller Function

    class Controller extends ApiController
    {
    public function sayHello(SayHelloRequest $request)
    {
    $helloMessage = app(SayHelloAction::class)->run();

    $this->json([
    $helloMessage
    ]);
    }
    }

    This function takes a Request class SayHelloRequest to automatically checks if the user has the right access to this endpoint. Only if the user has access, it proceeds to the function body.

    Then the function calls an Action (SayHelloAction) to perform the business logic.

    Sample Action

    class SayHelloAction extends Action
    {
    public function run()
    {
    return 'Hello World!';
    }
    }

    The Action can do anything then return a result (could be an Object, a String or anything).

    When the Action finishes its job, the controller function gets ready to build a response.

    Json responses can be built using the helper function json ($this->json(['foo' => 'bar']);).

    Sample User Response

    [
    "Hello World!"
    ]
    - + \ No newline at end of file diff --git a/docs/11.x/getting-started/software-architectural-patterns/index.html b/docs/11.x/getting-started/software-architectural-patterns/index.html index 97cd39189..4111b910f 100644 --- a/docs/11.x/getting-started/software-architectural-patterns/index.html +++ b/docs/11.x/getting-started/software-architectural-patterns/index.html @@ -4,7 +4,7 @@ Architecture | Apiato - + @@ -14,7 +14,7 @@ App\Containers\SectionName\Printer).
  • Container MAY be named anything, however a good practice is to name it to its most important Model name. Example: If the User Story is (User can create a Store and Store can have Items) then we you could have 3 Containers (User, Store and Item).
  • - + \ No newline at end of file diff --git a/docs/11.x/index.html b/docs/11.x/index.html index 338ea0ccf..db839c61f 100644 --- a/docs/11.x/index.html +++ b/docs/11.x/index.html @@ -4,13 +4,13 @@ Requirements | Apiato - +
    Version: 11.x

    Requirements

    Requirements

    • GIT
    • PHP >= 8.0.2
    • Composer
    • PHP Extensions:
      • OpenSSL PHP Extension
      • PDO PHP Extension
      • Mbstring PHP Extension
      • Tokenizer PHP Extension
      • BCMath PHP Extension (required when the Hash ID feature is enabled)
      • Intl Extension (required when you use the Localization Container)
    - + \ No newline at end of file diff --git a/docs/11.x/main-components/actions/index.html b/docs/11.x/main-components/actions/index.html index a526c8432..dd7d90cf5 100644 --- a/docs/11.x/main-components/actions/index.html +++ b/docs/11.x/main-components/actions/index.html @@ -4,7 +4,7 @@ Actions | Apiato - + @@ -17,7 +17,7 @@ automatically rolled-back from the database. However, respective operations on the file system (e.g., you may also have uploaded a profile picture for this Team already) need to be performed manually!

    Typically, you may want to use the transactionalRun() on the Controller level!

    - + \ No newline at end of file diff --git a/docs/11.x/main-components/controllers/index.html b/docs/11.x/main-components/controllers/index.html index 8c85a29ab..edf808ce8 100644 --- a/docs/11.x/main-components/controllers/index.html +++ b/docs/11.x/main-components/controllers/index.html @@ -4,7 +4,7 @@ Controllers | Apiato - + @@ -17,7 +17,7 @@ This function allows including metadata in the response.

    $metaData = ['total_credits', 10000];

    return $this->withMeta($metaData)->transform($receipt, ReceiptTransformer::class);

    json This function allows passing array data to be represented as json.

    return $this->json([
    'foo': 'bar'
    ])

    Other functions

    • accepted
    • deleted
    • noContent
    • // Some functions might not be documented, so refer to the vendor/apiato/core/Traits/ResponseTrait.php and see the public functions.
    - + \ No newline at end of file diff --git a/docs/11.x/main-components/exceptions/index.html b/docs/11.x/main-components/exceptions/index.html index 8ed32d46e..f67393f9a 100644 --- a/docs/11.x/main-components/exceptions/index.html +++ b/docs/11.x/main-components/exceptions/index.html @@ -4,13 +4,13 @@ Exceptions | Apiato - +
    Version: 11.x

    Exceptions

    Definition & Principles

    Read Porto SAP Documentation (#Exceptions).

    Rules

    • All Exceptions MUST extend App\Ship\Parents\Exceptions\Exception.
    • Shared (general) Exceptions between all Containers SHOULD be created in the Exceptions Ship folder (app/Ship/Exceptions/*).
    • Every Exception SHOULD have two properties code and message. You can override those values while throwing the error.

    Folder Structure

     - App
    - Containers
    - {section-name}
    - {container-name}
    - Exceptions
    - AccountFailedException.php
    - ...

    - Ship
    - Exceptions
    - CreateResourceFailedException.php
    - NotFoundException.php
    - ...

    Code Samples

    Demo Exception

    class DemoException extends Exception
    {
    public $code = Response::HTTP_CONFLICT;
    public $message = 'This is a demo exception.';
    }

    Usage from anywhere

    throw new AccountFailedException();

    Usage with errors

    throw (new AccountFailedException())->withErrors(['email' => 'Email already in use']);
    throw (new AccountFailedException())->withErrors(['email' => ['Email already in use', 'Another message']]);

    Usage with errors and localization

    For localization, you can use the Localization Container

    // translation strings are automatically translated if the translations are found.
    throw (new AccountFailedException())->withErrors(['email' => 'appSection@user::exceptions.email-taken']);

    Response:

    {
    "message": "The exception error message.",
    "errors": {
    "email": [
    "The email has already been taken."
    ]
    }
    }

    Usage with Log for Debugging

    throw (new AccountFailedException())->debug($e); // debug() accepts string or \Exception instance

    Usage and overriding the default

    throw new AccountFailedException('I am the message to be displayed to the user');
    - + \ No newline at end of file diff --git a/docs/11.x/main-components/models/index.html b/docs/11.x/main-components/models/index.html index 3864a6365..4e8cb2c21 100644 --- a/docs/11.x/main-components/models/index.html +++ b/docs/11.x/main-components/models/index.html @@ -4,13 +4,13 @@ Models | Apiato - +
    Version: 11.x

    Models

    Definition & Principles

    Read Porto SAP Documentation (#Models).

    Rules

    • All Models MUST extend from App\Ship\Parents\Models\Model.
    • If the name of a model differs from the Container name you have to implement model() method in the repository - more details.

    Folder Structure

     - App
    - Containers
    - {section-name}
    - {container-name}
    - Models
    - User.php
    - UserId.php
    - ...

    Code Sample

    class Demo extends Model
    {
    protected $table = 'demos';

    protected $fillable = [
    'label',
    'user_id'
    ];

    protected $hidden = [
    'token',
    ];

    protected $casts = [
    'total_credits' => 'float',
    ];

    protected $dates = [
    'created_at',
    'updated_at',
    ];

    public function user()
    {
    return $this->belongsTo(\App\Containers\AppSection\User\Models\User::class);
    }
    }

    Notice the Demo Model has a relationship with User Model, which lives in another Container.

    Casts

    The casts attribute can be used to parse any of the model's attributes to a specific type. In the code sample below we can cast total_credits to float.

    More information about the applicable cast-types can be found in the laravel eloquent-mutators documentation.

    You can place any dates inside the $dates to parse those automatically.

    - + \ No newline at end of file diff --git a/docs/11.x/main-components/requests/index.html b/docs/11.x/main-components/requests/index.html index 6f9eb9841..f01b90bf5 100644 --- a/docs/11.x/main-components/requests/index.html +++ b/docs/11.x/main-components/requests/index.html @@ -4,7 +4,7 @@ Requests | Apiato - + @@ -25,7 +25,7 @@ function.

    This helper, in turn, allows to "redefine" keys in the request for subsequent processing. Consider the following example request:

    {
    "data" : {
    "name" : "John Doe"
    }
    }

    Your Task to process this data, however, requests the field data.name as data.username. You can call the helper like this:

    $request->mapInput([
    'data.name' => 'data.username',
    ]);

    The resulting structure would look like this:

    {
    "data" : {
    "username" : "John Doe"
    }
    }

    Storing Data on the Request

    During the Request life-cycle you may want to store some data on the request object and pass it to other SubActions (or Tasks).

    To store some data on the request use:

    $request->keep(['someKey' => $someValue]);

    To retrieve the data back at any time during the request life-cycle use:

    $someValue = $request->retrieve('someKey');

    Unit Testing for Actions (Request)

    Since we're passing Request objects to Actions. When writing unit tests we need to create fake Request just to pass it to the Action with some fake data.

    // creating
    $request = RegisterUserRequest::injectData($data);

    Example One:

    $data = [
    'email' => 'john@doe.test',
    'name' => 'John Doe',
    'password' => 'so-secret',
    ];

    // create request object with some data
    $request = RegisterUserRequest::injectData($data);

    // create instance of the Action
    $action = app(RegisterUserAction::class)->run($request);

    // do any kind of assertions..
    $this->assertInstanceOf(User::class, $user);

    Example Two (With Authenticated User):

    $data = [
    'store_id' => $this->encode($store->id),
    'items' => $orderItems,
    'recipient' => $receipient,
    ];

    $user = User::factory()->create();

    $request = MakeOrderRequest::injectData($data, $user);

    $order = app(MakeOrderAction::class)->run($request);
    - + \ No newline at end of file diff --git a/docs/11.x/main-components/routes/index.html b/docs/11.x/main-components/routes/index.html index b5639dc08..9a8437b47 100644 --- a/docs/11.x/main-components/routes/index.html +++ b/docs/11.x/main-components/routes/index.html @@ -4,13 +4,13 @@ Routes | Apiato - +
    Version: 11.x

    Routes

    Definition & Principles

    Read Porto SAP Documentation (#Routes).

    Rules

    • API Route files MUST be named according to their API's version, exposure and functionality. e.g. CreateOrder.v1.public.php, FulfillOrder.v2.public.php, CancelOrder.v1.private.php...

    • Web Route files are pretty similar to API web files, but they can be named anything.

    Folder Structure

     - app
    - Containers
    - {section-name}
    - {container-name}
    - UI
    - API
    - Routes
    - CreateItem.v1.public.php
    - DeleteItem.v1.public.php
    - CreateItem.v2.public.php
    - DeleteItem.v1.private.php
    - ApproveItem.v1.private.php
    - ...
    - WEB
    - Routes
    - main.php
    - ...

    Code Sample

    Web & API route

    Routes are defined exactly like the way you defined them in Laravel.

    Route::post('hello', [Controller::class, 'sayHello']);

    Protected Route (API)

    Route::get('users', [Controller::class, 'listAllUsers'])
    ->middleware(['auth:api']);

    Protect your Endpoints:

    Checkout the Authorization Page.

    Difference between Public & Private routes files

    Apiato has 2 types of endpoint, Public (External) mainly for third parties clients, and Private (Internal) for your own Apps. This will help to generate separate documentations for each and keep your internal API private.

    - + \ No newline at end of file diff --git a/docs/11.x/main-components/subactions/index.html b/docs/11.x/main-components/subactions/index.html index 179555eb1..e59f608ce 100644 --- a/docs/11.x/main-components/subactions/index.html +++ b/docs/11.x/main-components/subactions/index.html @@ -4,13 +4,13 @@ Sub Actions | Apiato - +
    Version: 11.x

    Sub Actions

    Definition & Principles

    Read Porto SAP Documentation (#Sub-Actions).

    Rules

    • All SubActions MUST extend from App\Ship\Parents\Actions\SubAction.

    Folder Structure

     - app
    - Containers
    - {section-name}
    - {container-name}
    - Actions
    - ValidateAddressSubAction.php
    - BuildOrderSubAction.php
    - ...

    Code Sample

    ExampleSubAction

    class ExampleSubAction extends SubAction
    {
    public function run(SomeRequest $request)
    {
    app(SomeTask::class)->run($request);
    }
    }
    note

    Every feature available for Actions, are also available in SubActions.

    - + \ No newline at end of file diff --git a/docs/11.x/main-components/tasks/index.html b/docs/11.x/main-components/tasks/index.html index e909f0cce..c9e1107ae 100644 --- a/docs/11.x/main-components/tasks/index.html +++ b/docs/11.x/main-components/tasks/index.html @@ -4,13 +4,13 @@ Tasks | Apiato - +
    Version: 11.x

    Tasks

    Definition & Principles

    Read Porto SAP Documentation (#Tasks).

    Rules

    • All Tasks MUST extend from App\Ship\Parents\Tasks\Task.

    Folder Structure

     - app
    - Containers
    - {section-name}
    - {container-name}
    - Tasks
    - ConfirmUserEmailTask.php
    - GenerateEmailConfirmationUrlTask.php
    - SendConfirmationEmailTask.php
    - ValidateConfirmationCodeTask.php
    - SetUserEmailTask.php
    - ...

    Code Sample

    Task

    class FindUserByIdTask extends Task
    {
    private $userRepository;

    public function __construct(UserRepository $userRepository)
    {
    $this->userRepository = $userRepository;
    }

    public function run($id)
    {
    try {
    $user = $this->userRepository->find($id);
    } catch (Exception $e) {
    throw new UserNotFoundException();
    }

    return $user;
    }
    }

    Task usage from an Action

    class ValidateUserEmailByConfirmationCodeAction extends Action
    {
    public function run($userId, $code)
    {
    app(ValidateConfirmationCodeTask::class)->run($userId, $code);
    $user = app(FindUserByIdTask::class)->run($userId);
    app(ConfirmUserEmailTask::class)->run($user);
    }
    }
    - + \ No newline at end of file diff --git a/docs/11.x/main-components/transformers/index.html b/docs/11.x/main-components/transformers/index.html index 64ae4116e..b38d3b33f 100644 --- a/docs/11.x/main-components/transformers/index.html +++ b/docs/11.x/main-components/transformers/index.html @@ -4,13 +4,13 @@ Transformers | Apiato - +
    Version: 11.x

    Transformers

    Definition & Principles

    Read Porto SAP Documentation (#Transformers).

    Rules

    • All API responses MUST be formatted via a Transformer.

    • Every Transformer SHOULD extend from App\Ship\Parents\Transformers\Transformer.

    • Each Transformer MUST have a transform() function.

    Folder Structure

     - app
    - Containers
    - {section-name}
    - {container-name}
    - UI
    - API
    - Transformers
    - UserTransformer.php
    - ...

    Code Samples

    Reward Transformer with Country relation

    class ItemTransformer extends Transformer
    {
    protected $availableIncludes = [
    'images',
    ];

    protected $defaultIncludes = [
    'roles',
    ];

    public function transform(Item $item)
    {
    $response = [
    'object' => $item->getResourceKey(),
    'id' => $item->getHashedKey(),
    'name' => $item->name,
    'description' => $item->description,
    'price' => (float)$item->price,
    'weight' => (float)$item->weight,
    'created_at' => $item->created_at,
    'updated_at' => $item->updated_at,
    'readable_created_at' => $item->created_at->diffForHumans(),
    'readable_updated_at' => $item->updated_at->diffForHumans(),
    ];

    // add more or modify data for Admins only
    $response = $this->ifAdmin([
    'real_id' => $item->id,
    'deleted_at' => $item->deleted_at,
    ], $response);

    return $response;
    }

    public function includeImages(Item $item)
    {
    return $this->collection($item->images, new ItemImageTransformer());
    }

    public function includeRoles(User $user)
    {
    return $this->collection($user->roles, new RoleTransformer());
    }
    }

    Usage from Controller (Single Item)

    $user = $this->getUser();

    $this->transform($user, UserTransformer::class);

    // more options are available

    Relationships (include)

    Loading relationships in Transformer (calling other Transformers):

    This can be done in 2 ways:

    1. By the User, he can specify what relations to return in response.

    2. By the Developer, define what relations to include at run time.

    From Front-end

    You can request data with their relationships directly from the API call using include=tags,user but first the Transformer need to have the availableIncludes defined with their functions like this:

    class AccountTransformer extends Transformer
    {
    protected $availableIncludes = [
    'tags',
    'user',
    ];

    public function transform(Account $account)
    {
    return [
    'id' => (int)$account->id,
    'url' => $account->url,
    'username' => $account->username,
    'secret' => $account->secret,
    'note' => $account->note,
    ];
    }

    public function includeTags(Account $account)
    {
    // use collection with `multi` relationship
    return $this->collection($account->tags, new TagTransformer());
    }

    public function includeUser(Account $account)
    {
    // use `item` with single relationship
    return $this->item($account->user, new UserTransformer());
    }
    }

    Now to get the Tags with the response when Accounts are requested pass the ?include=tags parameter with the [GET] request.

    To get Tags with User use the comma separator: ?include=tags,user.

    From Back-end

    From the controller you can dynamically set the DefaultInclude using (setDefaultIncludes) anytime you want.

    return $this->transform($rewards, ProductsTransformer::class)->setDefaultIncludes(['tags']);

    You need to have includeTags function defined on the transformer. Look at the full examples above.

    If you want to include a relation with every response from this transformer you can define the relation directly in the transformer on ($defaultIncludes)

    protected $availableIncludes = [
    'users',
    ];

    protected $defaultIncludes = [
    'tags',
    ];

    // ..

    You need to have includeUser and includeTags functions defined on the transformer. Look at the full examples above.

    Transformer Available helper functions:

    • user(): returns current authenticated user object.

    • ifAdmin($adminResponse, $clientResponse): merges normal client response with the admin extra or modified results, when current authenticated user is Admin. Look at the full examples above.

    • nullableItem($model->something, new SomethingTransformer()): it is a shorthand for

    $model->something ? $this->item($model->something, new SomethingTransformer()) : $this->primitive(null)

    For more information about the Transformers read this.

    - + \ No newline at end of file diff --git a/docs/11.x/main-components/views/index.html b/docs/11.x/main-components/views/index.html index d672edeff..19073887d 100644 --- a/docs/11.x/main-components/views/index.html +++ b/docs/11.x/main-components/views/index.html @@ -4,13 +4,13 @@ Views | Apiato - +
    Version: 11.x

    Views

    Definition & Principles

    Read Porto SAP Documentation (#Views).

    Rules

    • Views SHOULD be created inside the Containers, and they will be automatically available for use in the Web Controllers.

    Folder Structure

     - app
    - Containers
    - {section-name}
    - {container-name}
    - UI
    - WEB
    - Views
    - welcome.php
    - profile.php
    - ...

    Code Sample

    Welcome page View

    <!DOCTYPE html>
    <html>
    <head>
    <title>Welcome</title>
    </head>
    <body>
    <div class="container">
    <div class="content">
    <div class="title">Welcome</div>
    </div>
    </div>
    </body>
    </html>

    Usage From Controller

    class Controller extends WebController
    {
    public function sayWelcome()
    {
    return view('just-welcome');
    }
    }

    Namespaces

    • By default, all Views are namespaced as the camelCase of its Section name + @ + camelCase of its Container name.

    For example, a view named welcome-page inside MySection > MyContainer can be accessed like this: view(mySection@myContainer::welcome-page)

    If you try to access it without the namespace view('just-welcome'), it will not find your View.

    note

    View files in Ship folder are exception to this and will be namespaced with the word "ship" instead of section name, e.g. view(ship::welcome-page)

    - + \ No newline at end of file diff --git a/docs/11.x/miscellaneous/tasks-queuing/index.html b/docs/11.x/miscellaneous/tasks-queuing/index.html index b554139b6..06bdfa65a 100644 --- a/docs/11.x/miscellaneous/tasks-queuing/index.html +++ b/docs/11.x/miscellaneous/tasks-queuing/index.html @@ -4,7 +4,7 @@ Tasks Queuing | Apiato - + @@ -18,7 +18,7 @@

    The only addition to the Laravel's queues in Apiato, is that by default, apiato detects which queue driver you are planning to use (based on the configs), to create the migration files required, in case type database is used.

    if (Config::get('queue.default') == 'database')
    {
    // do something
    }

    (refer to app/Ship/Migrations/ folder for more details).

    Beanstalkd

    In order to use Beanstalkd as your queue driver, you need to require the "pda/pheanstalk": "^4.0" package first. You can include this in any composer.json file you want.

    Further reading

    More info at Laravel Docs.

    - + \ No newline at end of file diff --git a/docs/11.x/miscellaneous/tasks-scheduling/index.html b/docs/11.x/miscellaneous/tasks-scheduling/index.html index 59e864a11..7b37317b6 100644 --- a/docs/11.x/miscellaneous/tasks-scheduling/index.html +++ b/docs/11.x/miscellaneous/tasks-scheduling/index.html @@ -4,7 +4,7 @@ Tasks Scheduling | Apiato - + @@ -18,7 +18,7 @@ See the Commands Page.

    Once you have your command ready, go to app/Ship/Kernels/ConsoleKernel.php and start adding the commands you need to schedule inside the schedule function.

    Example:

    protected function schedule(Schedule $schedule)
    {
    $schedule->command('apiato:welcome')->everyMinute();
    $schedule->job(new myJob)->hourly();
    $schedule->exec('touch me.txt')->dailyAt('12:00');
    // ...
    }

    More details here.

    note

    You do not need to register the commands with the $commands property or point to them in the commands() function. Apiato will do that automatically for you.

    Further reading

    More info at Laravel Docs.

    - + \ No newline at end of file diff --git a/docs/11.x/miscellaneous/tests-helpers/index.html b/docs/11.x/miscellaneous/tests-helpers/index.html index 1e83c48de..55a318cab 100644 --- a/docs/11.x/miscellaneous/tests-helpers/index.html +++ b/docs/11.x/miscellaneous/tests-helpers/index.html @@ -4,7 +4,7 @@ Tests Helpers | Apiato - + @@ -24,7 +24,7 @@ testing data.

    1. Go to app/Ship/Seeder/SeedTestingData.php seeder class, and create your live testing data.

    2. Run this command php artisan apiato:seed-test

    Debugging with PsySH

    For better debugging and development, you can open a runtime developer console while executing your test.

    Using PsySH (interactive debugger and REPL "read-eval-print loop" for PHP). The package is required by the Laravel Tinker Package.

    To use it set the breakpoint eval(\Psy\sh()); anywhere you want in any Actions, Controllers, Tasks... and run your test normally.

    - + \ No newline at end of file diff --git a/docs/11.x/optional-components/commands/index.html b/docs/11.x/optional-components/commands/index.html index 113c08275..56b8b6d4f 100644 --- a/docs/11.x/optional-components/commands/index.html +++ b/docs/11.x/optional-components/commands/index.html @@ -4,13 +4,13 @@ Commands | Apiato - +
    Version: 11.x

    Commands

    Definition

    • Commands are a Laravel artisan command. Laravel has its own default commands, and you can create your own as well.
    • Commands provide a way to interact with the Laravel app.
    • A Command can be scheduled by a Task scheduler, like Cron Job or by the Laravel built-in wrapper of the Cron Job "laravel scheduler".
    • Commands could be Closure based or Classes.
    • "dispatch" is the term that is usually used to call a Command.

    Principles

    • Containers MAY or MAY NOT have one or more Commands.

    • Every Command SHOULD call an Action to perform its job, and should not contain any business logic.

    • Ship may contain Application general Commands.

    Rules

    • All Commands MUST extend from App\Ship\Parents\Commands\ConsoleCommand.

    Folder Structure

    - app
    - Containers
    - {section-name}
    - {container-name}
    - UI
    - CLI
    - Commands
    - SayHelloCommand.php
    - ...
    - Ship
    - Commands
    - GeneralCommand.php
    - ...

    Code Samples

    A Simple Command

    class HelloWorldCommand extends ConsoleCommand
    {
    protected $signature = 'hello:world';
    protected $description = 'Hello World!';

    public function handle()
    {
    echo "Hello World :)\n";
    }
    }

    Usage from CLI (Terminal)

    php artisan hello:world

    Schedule Commands Execution

    To Schedule the execution of a Command checkout the Tasks Scheduling page.

    Define Consoles Closure Commands

    To define Console closure commands go to app/Ship/Commands/closures.php.

    Further reading

    More info at Laravel Docs.

    - + \ No newline at end of file diff --git a/docs/11.x/optional-components/configs/index.html b/docs/11.x/optional-components/configs/index.html index d7acad497..26757d05f 100644 --- a/docs/11.x/optional-components/configs/index.html +++ b/docs/11.x/optional-components/configs/index.html @@ -4,13 +4,13 @@ Configs | Apiato - +
    Version: 11.x

    Configs

    Definition

    Configs are files that contain configurations.

    In each Apiato container, there are two types of config files:

    • the container specific config file (a config file that contains the container specific configurations).
    • the container third party packages config files (a config file that belongs to a third party package, required by the composer file of the container).

    Principles

    • Your custom config files and third party packages config files, should be placed in the Container, unless it's too generic then it can be placed on the Ship Layer.
    • Containers can have as many config files as they need.

    Rules

    • When publishing a third party package config file, move it manually to its container or to the Ship Configs folder in case it is generic.
    • Framework config files (provided by Laravel) lives at the default config directory on the root of the project.
    • You SHOULD NOT add any config file to the root config directory.
    • The container specific config file, MUST be named this way:
      camelCase of its Section name + - + camelCase of its Container name, to prevent conflicts between third party packages and container specific packages.
      For example, config file inside MySection > MyContainer should be named like this: mySection-myContainer.php

    Folder Structure

    - app
    - Containers
    {section-name}
    - {container-name}
    - Configs
    - {section-name}-{container-name}.php
    - package-config-file1.php
    - ...
    - Ship
    - Configs
    - apiato.php
    - ...
    - config
    - app.php
    - ...

    Code Samples

    Example simple Config file

    // app/Containers/{SectionName}/{ContainerName}/Configs/{section-name}-{container-name}.php
    return [

    /*
    |--------------------------------------------------------------------------
    | Default Namespace
    |--------------------------------------------------------------------------
    */
    'namespace' => 'App',

    // some other config params here...

    You can access the respective configuration key like this:

    $value = Config::get('{section-name}-{container-name}.namespace');     // returns 'App'
    $value = config('{section-name}-{container-name}.namespace'); // same, but using laravel helper function
    Further reading

    More info at Laravel Docs.

    - + \ No newline at end of file diff --git a/docs/11.x/optional-components/criterias/index.html b/docs/11.x/optional-components/criterias/index.html index 3f75227f5..edeb93d7c 100644 --- a/docs/11.x/optional-components/criterias/index.html +++ b/docs/11.x/optional-components/criterias/index.html @@ -4,13 +4,13 @@ Criterias | Apiato - +
    Version: 11.x

    Criterias

    Definition

    Criterias are classes that hold and apply query condition when retrieving data from the database through a Repository.

    Without using a Criteria class, you can add your query conditions to a Repository or to a Model as scope, but with Criterias, your query conditions can be shared across multiple Models and Repositories. It allows you to define the query condition once and use it anywhere in the App.

    Principles

    • Every Container MAY have its own Criterias. However, shared Criterias SHOULD be created in the Ship layer.

    • A Criteria MUST not contain any extra code, if it needs data, the data SHOULD be passed to it from the Actions or the Task. It SHOULD not call any Task for data.

    Rules

    • All Criterias MUST extend from App\Ship\Parents\Criterias\Criteria.

    • Every Criteria SHOULD have an apply() function.

    Folder Structure

     - app
    - Containers
    - {section-name}
    - {container-name}
    - Data
    - Criterias
    - ColourRedCriteria.php
    - RaceCarsCriteria.php
    - ...
    - Ship
    - Criterias
    - CreatedTodayCriteria.php
    - NotNullCriteria.php
    - ...

    Code Samples

    A Shared Criteria

    class OrderByCreationDateDescendingCriteria extends Criteria
    {
    public function apply($model, PrettusRepositoryInterface $repository)
    {
    return $model->orderBy('created_at', 'desc');
    }
    }

    Usage from Task

    public function run()
    {
    $this->userRepository->pushCriteria(new OrderByCreationDateDescendingCriteria());
    return $this->userRepository->paginate();
    }

    Criteria Accepting Data Input

    class ThisUserCriteria extends Criteria
    {
    private $userId;

    public function __construct($userId)
    {
    $this->userId = $userId;
    }

    public function apply($model, PrettusRepositoryInterface $repository)
    {
    return $model->where('user_id', '=', $this->userId);
    }
    }

    Passing Data from Task to Criteria

    public function run($user)
    {
    $this->accountRepository->pushCriteria(new ThisUserCriteria($user->id));
    return $this->accountRepository->paginate();
    }

    Further reading

    More info at Laravel Docs.

    - + \ No newline at end of file diff --git a/docs/11.x/optional-components/events/index.html b/docs/11.x/optional-components/events/index.html index 8537b2792..c96dc2841 100644 --- a/docs/11.x/optional-components/events/index.html +++ b/docs/11.x/optional-components/events/index.html @@ -4,13 +4,13 @@ Events | Apiato - +
    Version: 11.x

    Events

    Definition

    • Events provide a simple observer implementation, allowing you to subscribe and listen for various events that occur in your application.
    • Events are classes that can be fired from anywhere in your application.
    • An event class will usually be bound to one, or many Events Listeners Classes or has those Listeners registered to listen to it.
    • "fire" is the term that is usually used to call an Event.

    Principles

    • Events can be fired from Actions and or Tasks. It's preferable to choose one place only. (Tasks are recommended).
    • Events SHOULD be created inside the Containers. However, general Events CAN be created in the Ship layer.

    Rules

    • Event classes CAN be placed inside the Containers in Events folders or on the Ship for the general Events.
    • All Events MUST extend from App\Ship\Parents\Events\Event.

    Folder Structure

    - App
    - Containers
    - {section-name}
    - {container-name}
    - Events
    - SomethingHappenedEvent.php
    - ...
    - Listeners
    - ListenToMusicListener.php
    - ...

    - Ship
    - Events
    - GlobalStateChanged.php
    - SomethingBiiigHappenedEvent.php
    - ...

    Usage

    In Laravel, you can create and register events in multiple way. Read Laravel documentation to learn more about Events.

    Your custom EventServiceProvider needs to be registered in the containers MainServiceProvider as well.

    Broadcasting

    To define Broadcasting channels go to app/Ship/Boardcasts/channels.php.

    Further reading

    More info at Laravel Docs.

    - + \ No newline at end of file diff --git a/docs/11.x/optional-components/factories/index.html b/docs/11.x/optional-components/factories/index.html index d3e0a40ba..a2a837341 100644 --- a/docs/11.x/optional-components/factories/index.html +++ b/docs/11.x/optional-components/factories/index.html @@ -4,13 +4,13 @@ Factories | Apiato - +
    Version: 11.x

    Factories

    Definition

    Factories (are a short name for Model Factories).

    Factories are used to generate some fake data with the help of Faker to be used for testing purposes.

    Factories are mainly used from Tests.

    Principles

    • Factories SHOULD be created in the Containers.

    Rules

    • All Factories MUST extend from App\Ship\Parents\Factories\Factory.

    Folder Structure

     - app
    - Containers
    - {section-name}
    - {container-name}
    - Data
    - Factories
    - UserFactory.php
    - ...

    Code Samples

    A User Model Factory

    class UserFactory extends Factory
    {
    protected $model = User::class;

    public function definition(): array
    {
    static $password;

    return [
    'name' => $this->faker->name,
    'email' => $this->faker->unique()->safeEmail,
    'password' => $password ?: $password = Hash::make('testing-password'),
    'email_verified_at' => now(),
    'remember_token' => Str::random(10),
    'is_admin' => false,
    ];
    }
    }

    Usage from Tests or Anywhere Else

    // creating 4 users
    User::factory()->count(4)->create();
    Further reading

    More info at Laravel Docs.

    - + \ No newline at end of file diff --git a/docs/11.x/optional-components/helpers/index.html b/docs/11.x/optional-components/helpers/index.html index 496b58e73..2fb78293e 100644 --- a/docs/11.x/optional-components/helpers/index.html +++ b/docs/11.x/optional-components/helpers/index.html @@ -4,13 +4,13 @@ Helpers | Apiato - +
    Version: 11.x

    Helpers

    Definition

    • Helpers are global PHP functions that you can call from anywhere in your application.
    • Helper files are simple PHP files that hold functions.

    Principles

    • Helpers SHOULD be created inside the Containers. However, general Helpers CAN be created in the Ship layer.
    • You can create as many helper files as you need, per container.
    • You can implement as many helper functions as you need, per helper file.
    • All Helper files will be autoloaded by the framework.

    Rules

    • Helpers CAN be placed inside the Containers in Helpers folder or on the Ship for the general Helpers.

    Folder Structure

    - App
    - Containers
    - {section-name}
    - {container-name}
    - Helpers
    - helpers.php
    - mix.php
    - ...

    - Ship
    - Helpers
    - helpers.php
    - mix.php
    - ...

    Usage

    if (!function_exists('add')) {
    function add(int $firstNumber, int $secondNumber): int
    {
    return $firstNumber + $secondNumber;
    }
    }
    - + \ No newline at end of file diff --git a/docs/11.x/optional-components/jobs/index.html b/docs/11.x/optional-components/jobs/index.html index 0d75c7bbb..7f43973ee 100644 --- a/docs/11.x/optional-components/jobs/index.html +++ b/docs/11.x/optional-components/jobs/index.html @@ -4,13 +4,13 @@ Jobs | Apiato - +
    Version: 11.x

    Jobs

    Definition

    • Jobs are simple classes that can do one thing or multiple related things.
    • Job is a name given to a class that is usually created to be queued (it's execution is usually deferred for later, after the execution of previous Jobs are completed).
    • Jobs can be scheduled to be executed later by a queuing mechanism (a queue system like beanstalkd).
    • When a Job class is dispatched, it performs its specific job and dies.
    • Laravel's queue worker will process every Job as it's pushed onto the queue.

    Principles

    • A Container MAY have more than one Job.

    Rules

    • All Jobs MUST extend from App\Ship\Parents\Jobs\Job.

    Folder Structure

    - app
    - Containers
    - {section-name}
    - {container-name}
    - Jobs
    - DoSomethingJob.php
    - DoSomethingElseJob.php

    Code Samples

    DemoJob

    class DemoJob extends Job
    {
    private $something;

    public function __construct(array $someData)
    {
    $this->something = $someData;
    }

    public function handle()
    {
    foreach ($this->something as $thing) {
    // do whatever you like
    }
    }
    }

    Check the parent Job class.

    Usage from Action

    // using helper function
    dispatch(new DemoJob($someData));

    // manually
    app(\Illuminate\Contracts\Bus\Dispatcher\Dispatcher::class)->dispatch(New DemoJob($someData));

    Execute Jobs Execution

    For running your Jobs checkout the Tasks Queuing page.

    Further reading

    More info at Laravel Docs.

    - + \ No newline at end of file diff --git a/docs/11.x/optional-components/languages/index.html b/docs/11.x/optional-components/languages/index.html index bb21e13ff..98f9e2843 100644 --- a/docs/11.x/optional-components/languages/index.html +++ b/docs/11.x/optional-components/languages/index.html @@ -4,14 +4,14 @@ Languages | Apiato - +
    Version: 11.x

    Languages

    Definition

    Languages are not real Components, they are just files that holds translations.

    Rules

    • Languages CAN be placed inside the Containers. However, the default laravel resources/lang languages files are still loaded and can be used as well.

    • All Translations are namespaced as the camelCase of its Section name + @ + camelCase of its Container name.
      For example, translation key inside a translation file named messages inside MySection > MyContainer can be accessed like this: __(mySection@myContainer::messages.welcome)

    Folder Structure

    - app
    - Containers
    - {section-name}
    - {container-name}
    - Resources
    - Languages
    - en
    - messages.php
    - users.php
    - ar
    - messages.php
    - users.php

    Usage

    Nothing much to show here, here's how you use translated strings:

    __('mySection@myContainer::messages.welcome');
    Further reading

    More info at Localization.

    - + \ No newline at end of file diff --git a/docs/11.x/optional-components/mails/index.html b/docs/11.x/optional-components/mails/index.html index 92d8c3556..57d98d8f2 100644 --- a/docs/11.x/optional-components/mails/index.html +++ b/docs/11.x/optional-components/mails/index.html @@ -4,13 +4,13 @@ Mails | Apiato - +
    Version: 11.x

    Mails

    Definition

    The Mail component allows you to describe an email and send it whenever needed.

    Principles

    • Containers MAY or MAY NOT have one or more Mail.

    • Ship may contain general Mails.

    Rules

    • All Notifications MUST extend from App\Ship\Parents\Mails\Mail.
    • Email Templates must be placed inside the Mail directory in a Templates directory app/Containers/{section}/{container}/Mails/Templates.

    Folder Structure

    - app
    - Containers
    - {section-name}
    - {container-name}
    - Mails
    - UserRegisteredMail.php
    - ...
    - Templates
    - user-registered.blade.php
    - ...
    - Ship
    - Mails
    - SomeMail.php
    - ...
    - Templates
    - some-template.blade.php
    - ...

    Code Samples

    A simple Mail

    class UserRegisteredMail extends Mail implements ShouldQueue
    {
    use Queueable;

    protected $user;

    public function __construct(User $user)
    {
    $this->user = $user;
    }

    public function build()
    {
    return $this->view('appSection@user::user-registered')
    ->to($this->user->email, $this->user->name)
    ->with([
    'name' => $this->user->name,
    ]);
    }
    }

    Usage from an Action

    Notifications can be sent from Actions or Tasks using the Mail Facade.

    Mail::send(new UserRegisteredMail($user));

    Email Templates

    Templates should be placed inside a folder Templates inside the Mail folder.

    To access a Mail template (same like accessing a web view) you must call the camelCase of its Section name + @ + camelCase of its Container name.

    In the example below we're using the user-registered.blade.php template in the AppSection Section > User Container.

    $this->view('appSection@user::user-registered');

    Configure Emails

    Open the .env file and set the from mail and address. This will be used globally whenever the from function is not called in the Mail.

    MAIL_FROM_ADDRESS=test@test.test
    MAIL_FROM_NAME="apiato"

    To use different email address in some classes add ->to($this->email, $this->name) to the build function in your Mail class.

    By default Apiato is configured to use Log Driver MAIL_DRIVER=log, you can change that from the .env file.

    Queueing A Notification

    To queue a notification you should use Illuminate\Bus\Queueable and implement Illuminate\Contracts\Queue\ShouldQueue.

    Further reading

    More info at Laravel Docs.

    - + \ No newline at end of file diff --git a/docs/11.x/optional-components/middlewares/index.html b/docs/11.x/optional-components/middlewares/index.html index 8ebf163c2..f12d3c262 100644 --- a/docs/11.x/optional-components/middlewares/index.html +++ b/docs/11.x/optional-components/middlewares/index.html @@ -4,7 +4,7 @@ Middlewares | Apiato - + @@ -12,7 +12,7 @@
    Version: 11.x

    Middlewares

    Definition

    Middleware provide a convenient mechanism for filtering HTTP requests entering your application.

    You can enable and disable Middlewares as you wish.

    Principles

    • There are two types of Middlewares, General (applied on all the Routes by default) and Endpoints Middlewares (applied on some Endpoints).

    • The Middlewares CAN be placed in Ship layer or Container layer depending on its roles.

    Rules

    • If a Middleware is written inside a Container then it MUST be registered inside that Container.

    • To register Middlewares in a Container the container needs to have a MiddlewareServiceProvider, and like all other Container Providers it MUST be registered in the MainServiceProvider of that Container.

    • General Middlewares SHOULD live in the Ship layer app/Ship/Middlewares/* and are registered in the app/Ship/Kernels/HttpKernel.

    • Third Party packages Middleware CAN be registered in Containers or on the Ship layer (wherever they make more sense). For example the jwt.auth middleware "provided by the JWT package" should be registered in the Authentication Container (Containers/AppSection/Authentication/Providers/MiddlewareServiceProvider.php).

    Folder Structure

     - App
    - Containers
    - {section-name}
    - {container-name}
    - Middlewares
    - WebAuthentication.php
    - Ship
    - Middleware
    - Http
    - EncryptCookies.php
    - VerifyCsrfToken.php

    Code Sample

    Middleware Registration Inside the Container Example

    class MiddlewareServiceProvider extends MiddlewareProvider
    {
    protected array $middlewares = [
    // ..
    ];

    protected array $middlewareGroups = [
    'web' => [
    // ..
    ],
    'api' => [
    // ..
    ],
    ];

    protected array $routeMiddleware = [
    // apiato User Authentication middleware for Web Pages
    'guest' => RedirectIfAuthenticated::class
    ];
    }

    Middleware Registration Inside the Ship Layer (HTTP Kernel)

    class HttpKernel extends LaravelHttpKernel
    {
    /**
    * The application's global HTTP middleware stack.
    *
    * These middleware are run during every request to your application.
    *
    * @var array
    */
    protected $middleware = [
    // Laravel middleware's
    // \App\Http\Middleware\TrustHosts::class,
    TrustProxies::class,
    HandleCors::class,
    PreventRequestsDuringMaintenance::class,
    ValidatePostSize::class,
    TrimStrings::class,
    ConvertEmptyStringsToNull::class,
    ];

    /**
    * The application's route middleware groups.
    *
    * @var array
    */
    protected $middlewareGroups = [
    'web' => [
    EncryptCookies::class,
    AddQueuedCookiesToResponse::class,
    StartSession::class,
    // \Illuminate\Session\Middleware\AuthenticateSession::class,
    ShareErrorsFromSession::class,
    VerifyCsrfToken::class,
    SubstituteBindings::class,
    ],

    'api' => [
    // Note: The "throttle" Middleware is registered by the RoutesLoaderTrait in the Core
    SubstituteBindings::class,
    ValidateJsonContent::class,
    ProcessETagHeadersMiddleware::class,
    ProfilerMiddleware::class,
    ],
    ];

    /**
    * The application's route middleware.
    *
    * These middleware may be assigned to groups or used individually.
    *
    * @var array
    */
    protected $routeMiddleware = [
    'auth' => Authenticate::class,
    // 'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
    'cache.headers' => SetCacheHeaders::class,
    // Note: The "can" Middleware is registered by MiddlewareServiceProvider in Authorization Container
    // 'can' => \Illuminate\Auth\Middleware\Authorize::class,
    // Note: The "guest" Middleware is registered by MiddlewareServiceProvider in Authentication Container
    // 'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
    'password.confirm' => RequirePassword::class,
    'signed' => ValidateSignature::class,
    'throttle' => ThrottleRequests::class,
    'verified' => EnsureEmailIsVerified::class,
    ];

    /**
    * The priority-sorted list of middleware.
    *
    * Forces non-global middleware to always be in the given order.
    *
    * @var string[]
    */
    protected $middlewarePriority = [
    EncryptCookies::class,
    StartSession::class,
    ShareErrorsFromSession::class,
    Authenticate::class,
    ThrottleRequests::class,
    AuthenticateSession::class,
    SubstituteBindings::class,
    Authorize::class,
    ];
    }
    Further reading

    More info at Laravel Docs.

    - + \ No newline at end of file diff --git a/docs/11.x/optional-components/migrations/index.html b/docs/11.x/optional-components/migrations/index.html index 38ecf6c1b..d6879beb4 100644 --- a/docs/11.x/optional-components/migrations/index.html +++ b/docs/11.x/optional-components/migrations/index.html @@ -4,13 +4,13 @@ Migrations | Apiato - +
    Version: 11.x

    Migrations

    Definition

    Migrations (are the short name for Database Migrations).

    Migrations are the version control of your database. They are very useful for generating and documenting the database tables.

    Principles

    • Migrations SHOULD be created inside the Containers folders.

    • Migrations will be autoloaded by the framework.

    Rules

    • No need to publish the DB Migrations. Just run the artisan migrate command and Laravel will read the Migrations from the Containers.

    Folder Structure

       - app
    - Containers
    - {section-name}
    - {container-name}
    - Data
    - Migrations
    - 2200_01_01_000001_create_something_table.php
    - ...

    Code Samples

    User CreateDemoTable Migrations

    class CreateDemoTable extends Migration
    {
    public function up()
    {
    Schema::create('demos', function (Blueprint $table) {
    $table->increments('id');
    // ...
    $table->timestamps();
    $table->softDeletes();
    });
    }

    public function down()
    {
    Schema::drop('demos');
    }
    }

    Further reading

    More info at Laravel Docs.

    - + \ No newline at end of file diff --git a/docs/11.x/optional-components/notifications/index.html b/docs/11.x/optional-components/notifications/index.html index acc57ada4..8fcd207de 100644 --- a/docs/11.x/optional-components/notifications/index.html +++ b/docs/11.x/optional-components/notifications/index.html @@ -4,7 +4,7 @@ Notifications | Apiato - + @@ -12,7 +12,7 @@
    Version: 11.x

    Notifications

    Definition

    Notifications allow you to inform the user about a state changes in your application.

    The Laravel notifications supports sending notifications across a variety of channels (mail, SMS, Slack, Database...).

    When using the Database channel, the notifications will be stored in a database to be displayed in your client interface.

    Principles

    • Containers MAY or MAY NOT have one or more Notification.

    • Ship MAY contain Application general Notifications.

    Rules

    • All Notifications MUST extend from App\Ship\Parents\Notifications\Notification.

    Folder Structure

    - app
    - Containers
    - {select-name}
    - {container-name}
    - Notifications
    - UserRegisteredNotification.php
    - ...
    - Ship
    - Notifications
    - SystemFailureNotification.php
    - ...

    Code Samples

    A Simple Notification

    class BirthdayReminderNotification extends Notification implements ShouldQueue
    {
    use Queueable;

    protected $notificationMessage;

    public function __construct($notificationMessage)
    {
    $this->notificationMessage = $notificationMessage;
    }

    public function toArray($notifiable)
    {
    return [
    'content' => $this->notificationMessage,
    ];
    }

    public function toMail($notifiable)
    {
    // $notifiable is the object you want to notify "e.g. user"
    return (new MailMessage)
    ->subject("Hello World")
    ->line("Hi, $notifiable->name")
    ->line($this->notificationMessage);
    }

    public function toSms($notifiable)
    {
    // ...
    }

    // ...
    }

    Usage from an Action or Task

    Notifications can be sent from Actions or Tasks using the Notification Facade.

    \Notification::send($user, new BirthdayReminderNotification($notificationMessage));

    Alternatively you can use the Illuminate\Notifications\Notifiable trait on the notifiable object "e.g. User" and then call it as follows:

    // call notify, found on the Notifiable trait
    $user->notify(new BirthdayReminderNotification($notificationMessage));

    Select Channels

    To select a notification channel, apiato have the app/Ship/Configs/notification.php config file where you can define the array of supported channels "e.g. SMS, Email, WebPush...", to be used for all your notifications.

    If you want to override the configuration for some notifications classes, or if you prefer to define the channels within each notification class itself, you can override the via function public function via($notifiable) in the notification class and define your channels.

    Checkout laravel notification channels for list of supported integrations.

    Queueing a Notification

    To queue a notification you should use Illuminate\Bus\Queueable and implement Illuminate\Contracts\Queue\ShouldQueue.

    Use DB channel

    Generally you need to generate the notification migration php artisan notifications:table, then run php artisan migrate, however just running the migration command will do the job, since Apiato already adds the _create_notifications_table.php in the default migrations files directory app/Ship/Migrations/.

    Further reading

    More info at Laravel Docs.

    - + \ No newline at end of file diff --git a/docs/11.x/optional-components/providers/index.html b/docs/11.x/optional-components/providers/index.html index e32d8fa26..56bed0244 100644 --- a/docs/11.x/optional-components/providers/index.html +++ b/docs/11.x/optional-components/providers/index.html @@ -4,7 +4,7 @@ Providers | Apiato - + @@ -14,7 +14,7 @@ In apiato those providers have been renamed and moved to the Ship Layer app/Ship/Parents/Providers/*:

    • AppServiceProvider
    • RouteServiceProvider
    • AuthServiceProvider
    • BroadcastServiceProvider
    • EventsServiceProvider
    note

    You should not touch those providers, instead you have to extend them from a containers providers in order to modify them. Example: the app/Containers/AppSection/Authentication/Providers/AuthProvider.php is extending the AuthServiceProvider to modify it.

    Those providers are not auto registered by default, thus writing any code there will not be available, unless you extend them. Once extended the child Provider should be registered in its Container Main Provider, which makes its parent available.

    This rule does not apply to the RouteServiceProvider since it's required by Apiato, this Provider is registered by the ShipProvider.

    Check How Service Providers are auto-loaded.

    Further reading

    More info at Laravel Docs.

    - + \ No newline at end of file diff --git a/docs/11.x/optional-components/repositories/index.html b/docs/11.x/optional-components/repositories/index.html index edfe5846f..c8673e482 100644 --- a/docs/11.x/optional-components/repositories/index.html +++ b/docs/11.x/optional-components/repositories/index.html @@ -4,13 +4,13 @@ Repositories | Apiato - +
    Version: 11.x

    Repositories

    Definition

    The Repository classes are an implementation of the Repository Design Pattern.

    Their major roles are separating the business logic from the data (or the data access Task).

    Repositories save and retrieves Models to/from the underlying storage mechanism.

    The Repository is used to separate the logic that retrieves the data and maps it to a Model, from the business logic that acts on the Model.

    Principles

    • Every Model SHOULD have a Repository.

    • A Model SHOULD always get accessed through its Repository. (Never accessed directly).

    Rules

    • All Repositories MUST extend from App\Ship\Parents\Repositories\Repository. Extending from this class will give you access to methods like (find, create, update and much more).

    • Repository name should be same as it's model name (model: Foo -> repository: FooRepository).

    • If a Repository belongs to a Model whose name is not equal to its Container name, then the Repository implement model() method like this.

    Folder Structure

     - app
    - Containers
    - {section-name}
    - {container-name}
    - Data
    - Repositories
    - UserRepository.php
    - ...

    Code Samples

    Demo Repository

    class DemoRepository extends Repository
    {
    protected $fieldSearchable = [
    'name' => 'like',
    'email' => '=',
    ];
    }

    Usage

    // paginate the data by 10
    $users = $userRepository->paginate(10);

    // search by 1 field
    $cars = $carRepository->findByField('colour', $colour);

    // searching multiple fields
    $offer = $offerRepository->findWhere([
    'offer_id' => $offer_id,
    'user_id' => $user_id,
    ])->first();

    //....

    Different Model and Container Name

    The model() method must be implemented when the model has different name than the container.

    class DemoRepository extends Repository
    {
    // ...

    public function model(): string
    {
    return Demo::class;
    }
    }

    Other Properties:

    API Query Parameters Property

    To enable query parameters (?search=text,...) in your API you need to set the property $fieldSearchable on the Repository class, to instruct the querying on your model. More details.

        protected $fieldSearchable = [
    'name' => 'like',
    'email' => '=',
    ];

    All other Properties

    Apiato uses the l5-repository package, to provide a lot of powerful features to the repository class.

    Further reading

    To learn more about all the properties you can use, visit the andersao/l5-repository package documentation.

    - + \ No newline at end of file diff --git a/docs/11.x/optional-components/seeders/index.html b/docs/11.x/optional-components/seeders/index.html index 356902f5b..9b0da026e 100644 --- a/docs/11.x/optional-components/seeders/index.html +++ b/docs/11.x/optional-components/seeders/index.html @@ -4,13 +4,13 @@ Seeders | Apiato - +
    Version: 11.x

    Seeders

    Definition

    Seeders (are a short name for Database Seeders).

    Seeders are classes made to seed the database with real data, this data usually should exist in the Application after the installation (Example: the default Users Roles and Permissions or the list of Countries).

    Principles

    • Seeders SHOULD be created in the Containers. (If the container is using a package that publishes a Seeder class, this class should be manually placed in the Container that make use of it. Do not rely on the package to place it in its right location).

    Rules

    • Seeders should be in the right directory inside the container to be loaded.

    • To avoid any conflict between containers seeders classes, you SHOULD always prepend the Seeders of each container with the container name. (Example: UserPermissionsSeeder, ItemPermissionsSeeder).

      note

      If 2 seeders classes have the same name but live in different containers, one of them will not be loaded. In these situations you can also prepend the seeder name with the section name

    • If you wish to order the seeding of the classes, you can just append _1, _2 to your classes.

    Folder Structure

     - App
    - Containers
    - {section-name}
    - {container-name}
    - Data
    - Seeders
    - ContainerNameRolesSeeder_1.php
    - ContainerNamePermissionsSeeder_2.php
    - ...

    Code Samples

    Demo Seeder

    class DemoSeeder_1 extends Seeder
    {
    public function run()
    {
    app(CreateRoleTask::class)->run('admin', 'Administrator', 'Administrator Role', 999);
    // ...
    }
    }
    note

    Same Seeder class is allowed to contain seeding for multiple Models.

    Run the Seeders

    After registering the Seeders you can run this command:

    php artisan db:seed

    Migrate & seed at the same time

    php artisan migrate --seed

    Testing Seeder Command

    It's useful sometimes to create a big set of testing data. apiato facilitates this task:

    1. Open app/Ship/Seeders/SeedTestingData.php and write your testing data here.
    2. Run this command any time you want this data available (example at staging servers):
    php artisan apiato:seed-test
    Further reading

    More info at Laravel Docs.

    - + \ No newline at end of file diff --git a/docs/11.x/optional-components/tests/index.html b/docs/11.x/optional-components/tests/index.html index a73857c68..5e72e99c1 100644 --- a/docs/11.x/optional-components/tests/index.html +++ b/docs/11.x/optional-components/tests/index.html @@ -4,13 +4,13 @@ Tests | Apiato - +
    Version: 11.x

    Tests

    Definition

    Tests classes are created to test if the Application classes are working as expected.

    The two most essential Test types for this architecture are the Unit Tests and the Functional Tests. However, Integration and Acceptance Tests can be used as well.

    Principles

    • Containers MAY be covered by all types of Tests.

    • Use Functional Tests to test Container Routes are doing what's expected from them.

    • Use Unit Tests to test Container Actions and Tasks are doing what's expected from them.

    Rules

    • All Container Test classes SHOULD extend from a Container Internal TestCase class {container-name}/Tests/TestCase.php. The container TestCase MUST extend main TestCase on Ship layer App\Ship\Parents\Tests\PhpUnit\TestCase. (Adding functions to the container TestCase allows sharing those functions between all Test classes of the Container).

    Folder Structure

     - app
    - Containers
    - {section-name}
    - {container-name}
    - Tests
    - TestCase.php // the container test case
    - Unit
    - CreateUserTest.php
    - UpdateUserTest.php
    - ...
    - UI
    - API
    - Tests
    - Functional
    - LoginTest.php
    - LogoutTest.php
    - ...
    - WEB
    - Tests
    - Functional
    - LoginTest.php
    - LogoutTest.php
    - ...
    - CLI
    - Tests
    - Functional
    - BackupDataTest.php
    - ...

    Code Sample

    class DeleteUserTest extends TestCase
    {
    protected $endpoint = 'delete@v1/users/{id}';

    protected array $access = [
    'roles' => '',
    'permissions' => 'delete-users',
    ];

    public function testDeleteExistingUser()
    {
    $user = $this->getTestingUser();

    $response = $this->injectId($user->id)->makeCall();

    $response->assertStatus(204);
    }
    }

    See the Tests Helpers Page

    - + \ No newline at end of file diff --git a/docs/11.x/optional-components/values/index.html b/docs/11.x/optional-components/values/index.html index 4e0efa104..687293602 100644 --- a/docs/11.x/optional-components/values/index.html +++ b/docs/11.x/optional-components/values/index.html @@ -4,7 +4,7 @@ Values | Apiato - + @@ -12,7 +12,7 @@
    Version: 11.x

    Values

    Definition & Principles

    Values are short names for the known "Value Objects" which are simple Objects, pretty similar to Models in the concept of representing data, but they do not get stored in the DB, thus they don't have ID's. They also do not hold functionality or change any state, they just hold data.

    A Value Object is an immutable object that is defined by its encapsulated attributes. We create Value Object when we need it to represent/serve/manipulate some data (attached as attributes), and we'll kill it later when we don't need it anymore, to recreate it again when needed.

    Rules

    • All Models MUST extend from App\Ship\Parents\Values\Value.

    Folder Structure

    - App
    - Containers
    - {section-name}
    - {container-name}
    - Values
    - Output.php
    - Region.php
    - ...

    Code Sample

    class Location extends Value
    {
    private $x = null;
    private $y = null;
    protected $resourceKey = 'locales';

    public function __construct($x, $y)
    {
    $this->x = $x;
    $this->y = $y;
    }

    public function getCoordinatesAsString()
    {
    return $this->x . ' - ' . $this->y;
    }
    }
    - + \ No newline at end of file diff --git a/docs/11.x/upgrade-guide/index.html b/docs/11.x/upgrade-guide/index.html index 874106065..a8662a9b2 100644 --- a/docs/11.x/upgrade-guide/index.html +++ b/docs/11.x/upgrade-guide/index.html @@ -4,7 +4,7 @@ Upgrade Guide | Apiato - + @@ -23,7 +23,7 @@ and the term New Project (referring to the new freshly installed Apiato 5.0).

    1) Download and install Apiato 5.0. See Application Setup.

    2) Delete the Containers directory app/Containers from the new project.

    3) Move the Containers directory app/Containers from the old project to the new project.

    4) Open this file app/Ship/composer.json in your old project and only copy the required dependencies, from the old project to the same file in the new project.

    5) Again, open the app/Ship/composer.json file in the new project, and remove the following dependencies: guzzlehttp/guzzle, prettus/l5-repository, barryvdh/laravel-cors, spatie/laravel-fractal, vinkla/hashids and johannesschobel/apiato-container-installer.

    6) Move and replace the following directories from the old project to the new project: config, public, resources, database and storage.

    7) Open config/app.php and replace App\Ship\Engine\Providers\PortoServiceProvider::class with Apiato\Core\Providers\ApiatoProvider::class.

    8) Move .gitignore, phpunit.xml and .env files, from the old project to the new project.

    9) Open the .env file on the new project and append this to it API_RATE_LIMIT_ENABLED=true.

    10) Open phpunit.xml file of the new project and delete this line from the file <file>./app/Ship/Engine/Loaders/FactoryMixer/FactoriesLoader.php</file>.

    11) If you had live testing data in your old project inside app/Ship/Seeders/Data/Testing/Seeders/TestingDataSeeder.php file, then copy that file content and past it in the new project inside app/Ship/Seeders/SeedTestingData.php. You will need to rename the class (not the file) from TestingDataSeeder to SeedTestingData, and you will need to update the namespace from namespace App\Ship\Seeders\Data\Testing\Seeders; to namespace App\Ship\Seeders;.

    12) If you ever used the HashIdTrait, you need to search and replace this namespace App\Ship\Engine\Traits\HashIdTrait with this Apiato\Core\Traits\HashIdTrait.

    13) Run composer update. If you got any error at this step, try to solve it or open an Issue.

    14) Move the .git directory from the old project to the new one. Add all changes git add . then commit git commit -m 'upgrade Apiato from 4.1 to 5.0'.

    15) Run your tests vendor/bin/phpunit.

    That's it :)

    How to manually upgrade older versions to 4.1?

    Use the Manual Upgrading Guide below.

    Manual Upgrading Guide

    These commands and examples, are compatible with the Apiato 8.0 upgrade. You can just copy/past.

    1) Checkout a new branch from your stable branch, to perform the upgrade.

    git checkout -b upgrade-apiato

    2) Configure a new remote (upstream) that points to the official Apiato repository.

    git remote add upstream https://github.com/apiato/apiato

    Verify the new upstream repository was added, by listing the current configured remote repositories.

    git remote -vv

    origin git@bitbucket.org:username/my-awesome-api.git (fetch)
    origin git@bitbucket.org:username/my-awesome-api.git (push)
    upstream git@github.com:apiato/apiato.git (fetch)
    upstream git@github.com:apiato/apiato.git (push)

    3) Checkout a new branch to hold the latest Apiato changes. This branch will be merged into your upgrade-apiato branch created above.

    git checkout -b apiato-{version}
    // Example: git checkout -b apiato-8.0

    4) Configure this branch to track an upstream specific branch.

    Replace {upstream-branch-name} with the branch name you want to upgrade to (for example 8.0).

    git fetch upstream {upstream-branch-name}
    // Example: git fetch upstream 8.0

    git branch --set-upstream-to upstream/{upstream-branch-name}
    // Example: git branch --set-upstream-to upstream/8.0

    Verify your local branch is tracking the Apiato specified upstream branch.

    git branch -vv

    apiato 77b4d945 [upstream/{upstream-branch-name}] ...
    master 77d302aa [origin/master] ...

    5) Make this branch identical to the remote upstream branch

    git reset --hard upstream/{upstream-branch-name}
    // Example: git reset --hard upstream/8.0

    Verify this branch now contains the latest changes from the upstream branch.

    git log

    6) Switch back to the upgrade-apiato branch

    git checkout upgrade-apiato

    7) Now lets merge the 2 branches. This step can be done in two ways:

    Option A: Merge all the changes together and solve the conflicts if any. (Recommended)

    You can execute the next command with different different parameters, below are 2 options to pick whatever feels safer to you. Do not execute both of them.

    A1: This will overwrite your changes with the upstream changes. (Try this first and if your tests failed then you can try the second one).

    git merge --allow-unrelated-histories --strategy-option=theirs apiato-{version}
    // Example: git merge --allow-unrelated-histories --strategy-option=theirs apiato-8.0

    A2: This will let you solve all the conflicts manually. (Can be the most secure choice, but it's time consuming as well.)

    git merge --allow-unrelated-histories apiato-{version}
    // Example: git merge --allow-unrelated-histories apiato-8.0

    Option B: Manually cherry pick the commits you likes to have:

    git log {upstream-branch-name}

    (copy each commit ID, one by one)

    git cherry-pick {commit-ID}

    (if you get any conflict solve it and keep moving)

    8) Compare your .env with the new .env-example and update it.

    9) Check everything is working. By running Composer install first then re-running your tests.

    • Read the changelog releases page.
    • You may want to update your custom containers dependencies, simply follow the composer install error outputs and bump each failing dependency. (Hint: visit each package releases page, and use the version which supports the supported version of Laravel).
    • You may need to fix the failing tests.
    composer install  &&  vendor/bin/phpunit

    10) Finally, merge the upgrade-apiato (which contains the upgraded changes) with your stable branch (could be master).

    git checkout master
    git merge upgrade-apiato

    php artisan -V

    Enjoy :)

    - + \ No newline at end of file diff --git a/docs/9.x/contribution-guide/index.html b/docs/9.x/contribution-guide/index.html index 75e10c492..75b88ce28 100644 --- a/docs/9.x/contribution-guide/index.html +++ b/docs/9.x/contribution-guide/index.html @@ -4,7 +4,7 @@ Contribution Guide | Apiato - + @@ -43,7 +43,7 @@ 3 - Make sure you write a complete Changelog, in the release description. 4 - Change the default branch on github to that new branch. 5 - If you updated the documentation and you should! then visit the documentation repository and merge the PR into master.

    - + \ No newline at end of file diff --git a/docs/9.x/core-features/admin-dashboard/index.html b/docs/9.x/core-features/admin-dashboard/index.html index f92ad2351..1a89ea035 100644 --- a/docs/9.x/core-features/admin-dashboard/index.html +++ b/docs/9.x/core-features/admin-dashboard/index.html @@ -4,13 +4,13 @@ Admin Dashboard | Apiato - +
    Version: 9.x

    Admin Dashboard

    Apiato does not recommend serving HTML pages. Instead, you should build your own Frontend App completely isolated from the Backend code.

    The provided Admin route

    How it works

    Visiting http://admin.apiato.test/dashboard will redirect you to a login page for admins.

    the default credentials are:

    It is up to you to build and customize your admin dashboard however you prefer.

    Change default Admin credentials

    you can change these default values from the seeder class in the Authorization container: app/Containers/Authorization/Data/Seeders/RolesAndPermissionsSeeder.php.

    - + \ No newline at end of file diff --git a/docs/9.x/core-features/api-docs-generator/index.html b/docs/9.x/core-features/api-docs-generator/index.html index b250656ec..57b846312 100644 --- a/docs/9.x/core-features/api-docs-generator/index.html +++ b/docs/9.x/core-features/api-docs-generator/index.html @@ -4,7 +4,7 @@ API Docs Generator | Apiato - + @@ -12,7 +12,7 @@
    Version: 9.x

    API Docs Generator

    Every great API needs a great Documentation.

    Apiato make writing and generating documentations very easy with the php artisan apiato:apidoc command.

    Alternatively you can generate a swagger doc from the apidoc comments, to do so run php artisan apiato:swagger command.

    Requirements

    • Install the ApiDocJs tool, the project directory

      • (npm install apidoc)
    • (Recommended) read the Routes page first.

    Usage

    1 - Write a PHP docblock on top of your endpoint like this:

    For more info about the parameters check out ApiDocJs documentation

    <?php

    /**
    * @apiGroup Authentication
    * @apiName UserLogin
    * @api {post} /users/login User Login
    * @apiDescription Description Here....
    * @apiVersion 1.0.0
    * @apiPermission none
    *
    * @apiHeader Accept application/json
    *
    * @apiParam {String} email
    * @apiParam {String} password
    *
    * @apiSuccessExample {json} Success-Response:
    * HTTP/1.1 200 OK
    * {
    * "data": {
    * "id": "owpzanmh",
    * "name": "Super Admin",
    * "email": "admin@admin.com"
    * ...
    * }
    *
    * @apiErrorExample {json} Error-Response:
    * {
    * "message":"401 Credentials Incorrect.",
    * "status_code":401
    * }
    *
    * @apiErrorExample {json} Error-Response:
    * {
    * "message":"Invalid Input.",
    * "errors":{
    * "email":[
    * "The email field is required."
    * ]
    * },
    * "status_code":422
    * }
    */

    $router->post('users/login', [
    'uses' => 'Controller@userLogin',
    ]);

    Note: All the Endpoints DocBlocks MUST be written inside Routes files, otherwise they won't be loaded.

    2 - Run the documentation generator command from the root directory:


    php artisan apiato:apidoc

    3 - Visit this URL's as shown in your terminal:

    NOTE: Every time you change the DocBlock of a Route file you need to run the apiato:apidoc command, to regenerate.

    Generate Swagger/OpenAPI JSON schema from apiDoc

    It's also possible to generate a Swagger/OpenAPI JSON schema from apiDoc with:


    php artisan apiato:swagger

    You can find the JSON schema at http://apiato.test/api/private/documentation/swagger/swagger.json

    Error: ApiDoc not found !!

    If you get an error (apidoc not found),

    1. open the container config file Containers/Documentation/Configs/apidoc.php

    2. edit the executable path to $(npm bin)/apidoc or to however you access the apidoc tool on your machine.

    <?php
    /*
    |--------------------------------------------------------------------------
    | Executable
    |--------------------------------------------------------------------------
    |
    | Specify how you run or access the `apidoc` tool on your machine.
    |
    */

    'executable' => 'apidoc',

    Shared response for faster updating and less outdated responses:

    To prevent duplicating the responses between routes, let's create a shared response for each object.

    Example: _user.v1.public.php will contain all responses (single, multiple...) of the User:

    <?php

    /**
    * @apiDefine UserSuccessSingleResponse
    * @apiSuccessExample {json} Success-Response:
    HTTP/1.1 200 OK
    {
    "data":{
    "object":"User",
    "id":eqwja3vw94kzmxr0,
    },
    "meta":{
    "include":[],
    "custom":[]
    }
    }
    */

    Usage of the shared User response from any endpoint:

    * @apiUse UserSuccessSingleResponse

    To avoid having to generate and update the Single and Multiple responses of the same object (recommended only for private API's) you can use the general shared Multiple Response * @apiUse GeneralSuccessMultipleResponse which you can find and modify it from app/Containers/Documentation/UI/API/Routes/*

    Edit the default generated values in the templates:

    Apiato generates by defaults 2 API documentations, each one has its own apidoc.json file. Both can be modified from the Documentation Containers in Containers/Documentation/ApiDocJs/

    apidoc.json Example file:

    {
    "name": "Apiato",
    "description": "Apiato (Private API) Documentation",
    "title": "Welcome to Apiato",
    "version": "1.0.0",
    "url" : "http://api.apiato.test",
    "template": {
    "withCompare": true,
    "withGenerator": true
    },
    "header": {
    "title": "API Overview",
    "filename": "app/Containers/Documentation/ApiDocJs/private/header.md"
    },
    "footer": {
    "title": "Footer",
    "filename": "app/Containers/Documentation/ApiDocJs/private/header.md"
    },
    "order": [

    ]
    }

    Change the Documentations URL's

    Edit the config file of the Documentation Container Containers/Documentation/Configs/apidoc.php

    <?php

    return [

    /*
    |--------------------------------------------------------------------------
    | Executable
    |--------------------------------------------------------------------------
    |
    | Specify how you run or access the `apidoc` tool on your machine.
    |
    */

    'executable' => 'apidoc',

    /*
    |--------------------------------------------------------------------------
    | API Types
    |--------------------------------------------------------------------------
    |
    | The `types` helps generating multiple documentations, by grouping them
    | under types names. You can add or remove any type. By default
    | `public` and `private` types are set.
    |
    | url: The url to access that generated API documentation.
    |
    | routes: The route file to read when generating this documentation.
    | Every route file will have the following name format:
    | `{endpoint-name}.v{version-number}.{documentation-type}.php`.
    |
    */

    'types' => [

    'public' => [
    'url' => 'api/documentation',
    'routes' => [
    'public',
    ],
    ],

    'private' => [
    'url' => 'api/private/documentation',
    'routes' => [
    'private',
    'public',
    ],
    ],
    ],


    /*
    |--------------------------------------------------------------------------
    | HTML files
    |--------------------------------------------------------------------------
    |
    | Specify where to put the generated HTML files.
    |
    */

    'html_files' => 'public/'


    // ...
    ];

    Edit the Documentation Header

    The header is usually the Overview of your API. It contains Info about authenticating users, making requests, responses, potential errors, rate limiting, pagination, query parameters and anything you want.

    All this information is written in app/Containers/Documentation/ApiDocJs/shared/header.template.md file, and the same file is used as header for both private and public documentations.

    To edit the content just open the markdown file in any markdown editor and edit it.

    You will notice some variables like {{rate-limit}} and {{token-expires}}. Those are replaced when running apidoc:generate with real values from your application configuration files.

    Feel free to extend them to include more info about your API from the app/Containers/Documentation/Actions/ProcessMarkdownTemplatesAction.php class.

    - + \ No newline at end of file diff --git a/docs/9.x/core-features/api-versioning/index.html b/docs/9.x/core-features/api-versioning/index.html index d8b5e0e78..e5b61d4e9 100644 --- a/docs/9.x/core-features/api-versioning/index.html +++ b/docs/9.x/core-features/api-versioning/index.html @@ -4,13 +4,13 @@ API Versioning | Apiato - +
    Version: 9.x

    API Versioning

    Since Laravel does not support API versioning, apiato provide a very easy way to implement versioning for your API.

    How it works

    Create:

    When creating a new API endpoint, specify the version number in the route file name following this naming format {endpoint-name}.{version-number}.{documentation-name}.php.

    Example:

    • MakeOrder.v1.public.php
    • MakeOrder.v2.public.php
    • ListOrders.v1.private.php

    Use:

    Automatically the endpoint inside that route file will be accessible by adding the version number to the URL.

    Example:

    • http://api.apiato.test/v1/register
    • http://api.apiato.test/v1/orders
    • http://api.apiato.test/v2/stores/123

    Version the API in header instead of URL

    First remove the URL version prefix:

    1. Edit app/Ship/Configs/apiato.php, set prefix to 'enable_version_prefix' => 'false',.
    2. Implement the Header versioning anyway you prefer. (this is not implemented in Apiato yet. Consider a contribution).
    - + \ No newline at end of file diff --git a/docs/9.x/core-features/authentication/index.html b/docs/9.x/core-features/authentication/index.html index 8a5369f42..c6c12cee1 100644 --- a/docs/9.x/core-features/authentication/index.html +++ b/docs/9.x/core-features/authentication/index.html @@ -4,7 +4,7 @@ Authentication | Apiato - + @@ -60,7 +60,7 @@ It will send you an email with a link when you make a request to that link, it will call the /password-reset endpoint.

    Note: For security reason, make sure the reset password URL is set in app/Containers/User/Configs/user-container.php, and given to the client App, to be sent as parameter when calling the /password-forgot.

    Note: You must set up the email to get this function to work, however for testing purposes set the MAIL_DRIVER=log in your .env file in order to the see the email content in the log file laravel.log.

    Social Authentication

    For Social Authentication visit the Social Authentication page.

    - + \ No newline at end of file diff --git a/docs/9.x/core-features/authorization/index.html b/docs/9.x/core-features/authorization/index.html index 874683a4d..72d74e223 100644 --- a/docs/9.x/core-features/authorization/index.html +++ b/docs/9.x/core-features/authorization/index.html @@ -4,7 +4,7 @@ Authorization | Apiato - + @@ -15,7 +15,7 @@ User has a permission to read articles, moderator can manage comments and admin can create articles. User has a level 1, moderator level 2 and admin level 3. It means, moderator and administrator has also permission to read articles, but administrator can manage comments as well.

    if ($user->getRoleLevel() > 10) {
    //
    }

    If user has multiple roles, the getRoleLevel() method returns the highest one.

    If you don't need the permissions inheriting feature, simply ignore the optional level parameter when creating roles.

    - + \ No newline at end of file diff --git a/docs/9.x/core-features/code-generator/index.html b/docs/9.x/core-features/code-generator/index.html index 40f6a8b9d..a234aa431 100644 --- a/docs/9.x/core-features/code-generator/index.html +++ b/docs/9.x/core-features/code-generator/index.html @@ -4,7 +4,7 @@ Code Generator | Apiato - + @@ -17,7 +17,7 @@ file needs to be the same as in vendor/apiato/core/Generator/Stubs.

    Say, if you like to change the config.stub, simply copy the file to app/Ship/Generators/CustomStubs/config.stub and start adapting it to your needs.

    If you run the respective command (e.g., in this case php artisan apiato:generate:configuration) this would read your specific config.stub file instead the pre-defined one!

    Contributing

    If you would like to add your own generators, please check out the Contribution Guide.

    For AngularJS 2 Users

    Checkout this awesome CRUD Containers generator package for Angular 2.4+.

    - + \ No newline at end of file diff --git a/docs/9.x/core-features/data-caching/index.html b/docs/9.x/core-features/data-caching/index.html index 30a7b4e6e..366440f03 100644 --- a/docs/9.x/core-features/data-caching/index.html +++ b/docs/9.x/core-features/data-caching/index.html @@ -4,13 +4,13 @@ Data Caching | Apiato - +
    Version: 9.x

    Data Caching

    Enable / Disable Eloquent Query Caching

    By default caching is disabled.

    To enable it, go to app/Ship/Configs/repository.php config file and set cache > enabled => true, or set it from the .env file using ELOQUENT_QUERY_CACHE.

    More details can be found here.

    Users can skip the query caching and request new data by passing specific parameter to the Endpoint. Checkout the Query parameters page.

    Change different caching settings

    You can use different cache setting for each repository.

    To set cache settings on each repository, first the caching must be enabled, second you need to set some properties on the repository class to override the default values.

    For an example look at the app/Containers/Countries/Data/Repositories/CountryRepository.php class. For more details about all the properties refer to the L5 repository package documentation.

    Note: you don't need to use the CacheableRepository trait or implement the CacheableInterface since they both exist on the Abstract repository class (App\Ship\Parents\Repositories\Repository).

    - + \ No newline at end of file diff --git a/docs/9.x/core-features/default-endpoints/index.html b/docs/9.x/core-features/default-endpoints/index.html index ba6bc9169..8f161f98a 100644 --- a/docs/9.x/core-features/default-endpoints/index.html +++ b/docs/9.x/core-features/default-endpoints/index.html @@ -4,13 +4,13 @@ Default Endpoints | Apiato - +
    Version: 9.x

    Default Endpoints

    Apiato comes shipped with many useful API endpoints for speeding up the development process.

    You can see the endpoints in three ways:

    • In Terminal, by running php artisan route:list.
    • In Browser, by generating the beautiful detailed documentation. See the API Docs Generator page for more details.
    • In Code, by navigating to the Routes folder of each container's UI.

    Screenshot showing the result of route:list:

    - + \ No newline at end of file diff --git a/docs/9.x/core-features/etag/index.html b/docs/9.x/core-features/etag/index.html index 5d79b2ba4..f6739f738 100644 --- a/docs/9.x/core-features/etag/index.html +++ b/docs/9.x/core-features/etag/index.html @@ -4,7 +4,7 @@ ETag | Apiato - + @@ -12,7 +12,7 @@
    Version: 9.x

    ETag

    ETag Middleware

    Apiato provides an ETag Middleware (app/Ship/Middlewares/Http/ProcessETagHeadersMiddleware.php) that implements the Shallow technique. It can be used to reduce bandwidth on the client side (especially for Mobile devices).

    By default, the feature is disabled. To enable it go to app/Ship/Configs/apiato.php and set use-etag to true. Of course your client should send the If-None-Match HTTP Header (= etag) in his request for this feature to work properly.

    - + \ No newline at end of file diff --git a/docs/9.x/core-features/hash-id/index.html b/docs/9.x/core-features/hash-id/index.html index e37343d06..5e98d7a7b 100644 --- a/docs/9.x/core-features/hash-id/index.html +++ b/docs/9.x/core-features/hash-id/index.html @@ -4,13 +4,13 @@ Hash ID | Apiato - +
    Version: 9.x

    Hash ID

    Hashing your internal ID's, is a very helpful feature for security reasons (to prevent some hack attacks) and business reasons (to hide the real total records from your competitors).

    Enable Hash ID

    Set the HASH_ID=true in the .env file.

    Also, with the feature make sure to always use the getHashedKey() on any model, whenever you need to return an ID (mainly from transformers) weather hashed ID or not.

    Example:


    'id' => $user->getHashedKey(),

    Note: if the feature is set to false HASH_ID=false the getHashedKey() will return the normal ID.

    Usage

    There are 2 ways an ID's can be passed to your system via the API:

    In URL example: www.apiato.test/items/abcdef.

    In parameters example: [GET] or [POST] www.apiato.test/items?id=abcdef.

    in both cases you will need to inform your API about what's coming form the Request class.

    Checkout the Requests page. After setting the $decode and $urlParameters properties on your Request class, the ID will be automatically decoded for you, to apply validation rules on it or/and use it from your controller ($request->id will return the decoded ID).

    Configuration

    You can change the default length and characters used in the ID from the config file app/Ship/Configs/hashids.phpor in the .env file by editing the HASH_ID_LENGTH value.

    From Apiato Version 7.4.*

    You can set the HASH_ID_KEY in the .env file to any random string. You can generate this from any of the online random string generators, or run head /dev/urandom | tr -dc 'A-Za-z0-9!"#$%&'\''()*+,-./:;<=>?@[\]^_{|}~' | head -c 32 ; echo on the linux commandline. Apiato defaults to the APP_KEY should this not be set.

    The HASH_ID_KEY acts as the salt during hashing of the ID. This should never be changed in production as it renders all previously generated IDs quite difficult to decode and recover.

    Testing

    In your tests you must hash the ID's before making the calls, because if you tell your Request class to decode an ID for you, it will throw an exception when the ID is not encoded.

    for Parameter ID's

    Always use getHashedKey() on your models when you want to get the ID

    Example:

    $data = [
    'roles_ids' => [
    $role1->getHashedKey(),
    $role2->getHashedKey(),
    ],
    'user_id' => $randomUser->getHashedKey(),
    ];
    $response = $this->makeCall($data);

    Or you can do this manually Hashids::encode($id);.

    for URL ID's

    You can use this helper function injectId($id, $skipEncoding = false, $replace = '{id}').

    Example:

    $response = $this->injectId($admin->id)->makeCall();

    More details on the Tests Helpers page.

    Availability

    You can use the Apiato\Core\Traits\HashIdTrait to any model or class, in order to have the encode and decode functions.

    By default, you have access to these functions $this->encode($id) and $this->decode($id) from all your Tests class and Controllers.

    - + \ No newline at end of file diff --git a/docs/9.x/core-features/localization/index.html b/docs/9.x/core-features/localization/index.html index 9b4b2e27d..f256ce93d 100644 --- a/docs/9.x/core-features/localization/index.html +++ b/docs/9.x/core-features/localization/index.html @@ -4,7 +4,7 @@ Localization | Apiato - + @@ -36,7 +36,7 @@ language in this specific language (e.g., locale_name => Deutsch). Furthermore, the language name is outputted in the applications default name (e.g., configured in app.locale). This would result in default_name => German.

    The same applies to the regions that are defined (e.g., de-DE). Consequently, this results in locale_name => Deutschland and default_name = Germany.

    Tests

    To change the default language in your tests requests. You can set the env language in the phpunit.xml file.

    - + \ No newline at end of file diff --git a/docs/9.x/core-features/pagination/index.html b/docs/9.x/core-features/pagination/index.html index eb7306a52..35ae2dbc1 100644 --- a/docs/9.x/core-features/pagination/index.html +++ b/docs/9.x/core-features/pagination/index.html @@ -4,7 +4,7 @@ Pagination | Apiato - + @@ -16,7 +16,7 @@ you can manually override the $allowDisablePagination property in your specific Repository class. A requester can then get all data (with no pagination applied) by requesting api.domain.test/endpoint?limit=0. This will return all matching entities.

    Skip the Pagination Limit

    You can allow developers to skip the pagination limit as follows:

    First, you need to enable that feature from the server by setting PAGINATION_SKIP to true (PAGINATION_SKIP=true).

    Second, inform the developers (users) to pass ?limit=0 with the request they wish to get all it's data un-paginated.

    - + \ No newline at end of file diff --git a/docs/9.x/core-features/payments/index.html b/docs/9.x/core-features/payments/index.html index 4f5c27baa..06ae28eed 100644 --- a/docs/9.x/core-features/payments/index.html +++ b/docs/9.x/core-features/payments/index.html @@ -4,7 +4,7 @@ Payments | Apiato - + @@ -38,7 +38,7 @@ need to create your own ChargeWithFooTask. This class, however, needs to implement the PaymentChargerInterface distributed via the Payment container. This interface, in turn, requires you to implement the charge() method.

    This method needs to connect to the FooService, create the payment and return a PaymentTransaction model.

    Finally, you need to register the new service. This can be done in the Payment\Configs\payment-container.php file. For the payment-container.gateways key, add the new entry for your Foo Payment Gateway. This may look like this:

        // ...
    'foo' => [
    'container' => 'Foo',
    'charge_task' => \App\Containers\Foo\Tasks\ChargeWithFooTask::class,
    ],
    // ...

    Basically, this entry points to the charger_task that handles, how to charge a User with the specific Payment Gateway.

    That's all!

    Mocking the real payment call for Testing

    <?php

    // mock the ChargeWithStripeService external API call
    $this->mockIt(ChargeWithStripeService::class)->shouldReceive('charge')->andReturn([
    'payment_method' => 'stripe',
    'description' => $payId
    ]);

    // mock the ChargeWithPaypalService external API call
    $this->mockIt(ChargeWithPaypalService::class)->shouldReceive('charge')->andReturn([
    'payment_method' => 'paypal',
    'description' => $payId
    ]);

    Checkout the Tests Helpers page for about Testing.

    - + \ No newline at end of file diff --git a/docs/9.x/core-features/profiler/index.html b/docs/9.x/core-features/profiler/index.html index 7852dccc3..4d712c2cc 100644 --- a/docs/9.x/core-features/profiler/index.html +++ b/docs/9.x/core-features/profiler/index.html @@ -4,14 +4,14 @@ Profiler | Apiato - +
    Version: 9.x

    Profiler

    Profiling is very important to optimize the performance of your application, and help you better understand what happens when a request is received, as well as it can speed up the debugging process.

    Apiato uses the third-party package laravel-debugbar (which uses the PHP Debug Bar), to collect the profiling data.

    By default, the laravel-debugbar package displays the profiling data in the browser. However, Apiato uses a middleware app/Ship/Middlewares/Http/ProfilerMiddleware.php to append the profiling data to the response.

    Sample Profiler response

    {
    // Actual Response Here...
    "_profiler": {
    "__meta": {
    "id": "X167f293230e3457f1bbd95d9c82aba4a",
    "datetime": "2017-09-22 18:45:27",
    "utime": 1506105927.799299,
    "method": "GET",
    "uri": "/",
    "ip": "172.20.0.1"
    },
    "messages": {
    "count": 0,
    "messages": []
    },
    "time": {
    "start": 1506105922.742068,
    "end": 1506105927.799333,
    "duration": 5.057265043258667,
    "duration_str": "5.06s",
    "measures": [
    {
    "label": "Booting",
    "start": 1506105922.742068,
    "relative_start": 0,
    "end": 1506105923.524004,
    "relative_end": 1506105923.524004,
    "duration": 0.7819359302520752,
    "duration_str": "781.94ms",
    "params": [],
    "collector": null
    },
    {
    "label": "Application",
    "start": 1506105923.535343,
    "relative_start": 0.7932748794555664,
    "end": 1506105927.799336,
    "relative_end": 0.00000286102294921875,
    "duration": 4.26399302482605,
    "duration_str": "4.26s",
    "params": [],
    "collector": null
    }
    ]
    },
    "memory": {
    "peak_usage": 13234248,
    "peak_usage_str": "12.62MB"
    },
    "exceptions": {
    "count": 0,
    "exceptions": []
    },
    "route": {
    "uri": "GET /",
    "middleware": "api, throttle:30,1",
    "domain": "http://api.apiato.test",
    "as": "apis_root_page",
    "controller": "App\\Containers\\Welcome\\UI\\API\\Controllers\\Controller@apiRoot",
    "namespace": "App\\Containers\\Welcome\\UI\\API\\Controllers",
    "prefix": "/",
    "where": [],
    "file": "app/Containers/Welcome/UI/API/Controllers/Controller.php:20-25"
    },
    "queries": {
    "nb_statements": 0,
    "nb_failed_statements": 0,
    "accumulated_duration": 0,
    "accumulated_duration_str": "0μs",
    "statements": []
    },
    "swiftmailer_mails": {
    "count": 0,
    "mails": []
    },
    "logs": {
    "count": 3,
    "messages": [
    {
    "message": "...",
    "message_html": null,
    "is_string": false,
    "label": "error",
    "time": 1506105927.694807
    },
    {
    "message": "...",
    "message_html": null,
    "is_string": false,
    "label": "error",
    "time": 1506105927.694811
    },
    {
    "message": "[2017-09-18 17:38:15] testing.INFO: New User registration. ID = 970ylqvaogmxnbdr | Email = apiato@mail.test. Thank you for signing up.\n</div>\n</body>\n</html>\n \n",
    "message_html": null,
    "is_string": false,
    "label": "info",
    "time": 1506105927.694812
    }
    ]
    },
    "auth": {
    "guards": {
    "web": "array:2 [\n \"name\" => \"Guest\"\n \"user\" => array:1 [\n \"guest\" => true\n ]\n]",
    "api": "array:2 [\n \"name\" => \"Guest\"\n \"user\" => array:1 [\n \"guest\" => true\n ]\n]"
    },
    "names": ""
    },
    "gate": {
    "count": 0,
    "messages": []
    }
    }
    }

    Configuration

    By default, the profiler feature is turned off. To turn it on edit the .env file and set DEBUGBAR_ENABLED=true.

    To control and modify the profiler response, you need to edit this config file app/Ship/Configs/debugbar.php.

    - + \ No newline at end of file diff --git a/docs/9.x/core-features/query-parameters/index.html b/docs/9.x/core-features/query-parameters/index.html index 3a9ac8a32..8e2b3f07e 100644 --- a/docs/9.x/core-features/query-parameters/index.html +++ b/docs/9.x/core-features/query-parameters/index.html @@ -4,7 +4,7 @@ Query Parameters | Apiato - + @@ -22,7 +22,7 @@ accepts driver as relationship (in the Available Relationships section).

    Nested Includes

    It is also possible to request "nested includes". Extend the example from above. Imagine, that a Driver may also have a relationship to an Address object. You can access this information as well by calling ?include=driver,driver.address.

    Of course, the address include is defined in the respective DriverTransformer that is used here.

    Usage:

    api.domain.test/endpoint?include=relationship

    Where to define the includes:

    Every Transformer can have 2 types of includes $availableIncludes and $defaultIncludes:

        protected $availableIncludes = [
    'products',
    'store',
    'recipients',
    ];

    protected $defaultIncludes = [
    'invoice',
    ];

    $defaultIncludes will not be listed in the response, only the $availableIncludes will be.

    Visit the Transformers page for more details.

    (provided by the Fractal Transformer)

    Caching skipping

    Note: You need to turn the Eloquent Query Caching ON for this feature to work. Checkout the Configuration Page "ELOQUENT_QUERY_CACHE".

    To run a new query and force disabling the cache on certain endpoints, you can use this parameter

    ?skipCache=true

    It's not recommended to keep skipping cache as it has bad impact on the performance.

    (provided by the L5 Repository)

    Configuration

    Most of these parameters are provided by the L5 Repository and configurable from the Ship/Configs/repository.php file. Some of them are built in house, or inherited from other packages such as Fractal.

    See the Query parameters from the User Developer perspective

    1) Generate the Default API documentation

    2) Visit the documentation URL

    More details in the API Docs Generator page.

    More Information

    For more details on these parameters check out these links:

    - + \ No newline at end of file diff --git a/docs/9.x/core-features/rate-limiting/index.html b/docs/9.x/core-features/rate-limiting/index.html index 67a648467..349b65de2 100644 --- a/docs/9.x/core-features/rate-limiting/index.html +++ b/docs/9.x/core-features/rate-limiting/index.html @@ -4,14 +4,14 @@ Rate Limiting | Apiato - +
    Version: 9.x

    Rate Limiting

    apiato uses the default Laravel middleware for rate limiting (throttling).

    All REST API requests are throttled to prevent abuse and ensure stability. The exact number of calls that your application can make per day varies based on the type of request you are making.

    The rate limit window is 1 minute per endpoint, with most individual calls allowing for 30 requests in each window.

    In other words, each user is allowed to make 30 calls per endpoint every 1 minute. (For each unique access token).

    To update these values go to app/Ship/Configs/apiato.php config file, or to the ENV file.

    'throttle' => [
    'enabled' => env('API_RATE_LIMIT_ENABLED', true),
    'attempts' => env('API_RATE_LIMIT_ATTEMPTS', '30'),
    'expires' => env('API_RATE_LIMIT_EXPIRES', '1'),
    ]
    API_RATE_LIMIT_ENABLED=true
    API_RATE_LIMIT_ATTEMPTS=30
    API_RATE_LIMIT_EXPIRES=1

    For how many hits you can preform on an endpoint, you can always check the header:

    X-RateLimit-Limit →30
    X-RateLimit-Remaining →29

    Enable/Disable Rate Limiting:

    The API rate limiting middleware is enabled and applied to all the Container Endpoints by default.

    To disable it set API_RATE_LIMIT_ENABLED to false in the .env file.

    - + \ No newline at end of file diff --git a/docs/9.x/core-features/requests-monitor/index.html b/docs/9.x/core-features/requests-monitor/index.html index 20c564c39..84c788908 100644 --- a/docs/9.x/core-features/requests-monitor/index.html +++ b/docs/9.x/core-features/requests-monitor/index.html @@ -4,13 +4,13 @@ Requests Monitor | Apiato - +
    Version: 9.x

    Requests Monitor

    Apiato provides a simple and easy way to monitor and log all the HTTP requests coming to your application.

    The request monitor can be very useful when testing and debugging your frontend Apps which consume your API. Especially when the frontend apps (Mobile, Web,...) are built by other developers who are far from you.

    The requests monitor is provided by the Debugger Container, by a RequestsMonitorMiddleware middleware.

    Enable requests logging

    From the .env file set REQUESTS_DEBUG to true.

    Now in order for this to start displaying the results you need to enable the debugging mode in Laravel by setting APP_DEBUG to true in the .env as well.

    Usage

    Simply tail the log file


    tail -f storage/logs/debugger.log

    Result

    Screenshot example:

    Change the default log file

    By default, everything is logged in the debugger.log file, to change the default file go to Debugger/Configs/debugger.php config file and set the file name:

    <?php

    /*

    |--------------------------------------------------------------------------
    | Log File
    |--------------------------------------------------------------------------
    |
    | What to name the log file in the `storage/log` path.
    |
    */

    'log_file' => 'debugger.log',

    This feature is provided by the Debugger Container via its RequestsMonitorMiddleware middleware.

    To see the results go ahead and Tail the default Laravel debug file tail -f storage/logs/laravel.log.

    Note: this will also not run in Testing environments, to enable it you need to manually edit the Middleware.

    - + \ No newline at end of file diff --git a/docs/9.x/core-features/search-query-parameter/index.html b/docs/9.x/core-features/search-query-parameter/index.html index dacdf46ef..34969d151 100644 --- a/docs/9.x/core-features/search-query-parameter/index.html +++ b/docs/9.x/core-features/search-query-parameter/index.html @@ -4,13 +4,13 @@ Search Query Parameter | Apiato - +
    Version: 9.x

    Search Query Parameter

    Below we'll see how to set up a Search Query Parameter, on a Model:

    1. Add searchable Fields on the Model Repository, all the other steps are normal steps
    <?php

    namespace App\Containers\User\Data\Repositories;

    use App\Containers\User\Contracts\UserRepositoryInterface;
    use App\Ship\Parents\Repositories\Repository;

    class UserRepository extends Repository implements UserRepositoryInterface
    {

    protected $fieldSearchable = [
    'name' => 'like',
    'id' => '=',
    'email' => '=',
    ];

    }
    1. Create basic list and search Task
    <?php

    namespace App\Containers\User\Tasks;

    use App\Containers\User\Contracts\UserRepositoryInterface;
    use App\Port\Action\Abstracts\Action;

    class ListUsersTask extends Action
    {
    private $userRepository;

    public function __construct(UserRepositoryInterface $userRepository)
    {
    $this->userRepository = $userRepository;
    }

    public function run($order = true)
    {
    return $this->userRepository->paginate();
    }
    }

    1. Create basic Action to call that basic Task, and maybe other Tasks later in the future when needed
    <?php

    namespace App\Containers\User\Actions;

    use App\Containers\User\Tasks\ListUsersTask;
    use App\Port\Action\Abstracts\Action;

    class ListAndSearchUsersAction extends Action
    {

    private $listUsersTask;

    public function __construct(ListUsersTask $listUsersTask)
    {
    $this->listUsersTask = $listUsersTask;
    }

    public function run($order = true)
    {
    return $this->listUsersTask->run($order);
    }
    }

    1. Use the Action from a Controller

    <?php

    public function listAllUsers()
    {
    $users = Apiato::call('User@ListAndSearchUsersAction');

    return $this->response->paginator($users, new UserTransformer());
    }

    1. Call it from anywhere as follows: [GET] http://api.apiato.com/users?search=Mahmoud@apiato.com
    - + \ No newline at end of file diff --git a/docs/9.x/core-features/social-authentication/index.html b/docs/9.x/core-features/social-authentication/index.html index 0bd65d78a..718f62229 100644 --- a/docs/9.x/core-features/social-authentication/index.html +++ b/docs/9.x/core-features/social-authentication/index.html @@ -4,14 +4,14 @@ Social Authentication | Apiato - +
    Version: 9.x

    Social Authentication

    For Social Authentication Apiato uses Socialite.

    Default Supported Auth Provide

    • Facebook
    • Twitter

    How Social Authentication Works

    1. The Client (Mobile or Web) sends a request to the Social Auth Provider (Facebook, Twitter..).
    2. The Social Auth Provider returns a Code (Tokens).
    3. The Client makes a call to the server (our server) and passes the Code (Tokens) retrieved from the Provider.
    4. The Server fetches the user data from the Social Auth Provider using the received Code (Tokens).
    5. The Server create new User from the collected social data and return the Authenticated User (If the user already created then it just returns it).

    Setup Social Authentication

    1) Create an App on the supported Social Auth provider.

    For the callback URL you can use this Apiato web endpoint http://apiato.test/auth/{provider}/callback (replace the provider with any of the supported providers facebook, twitter,..).

    2) Set the Tokens and Secrets in the .env file

        'facebook' => [
    'client_id' => env('AUTH_FACEBOOK_CLIENT_ID'), // App ID
    'client_secret' => env('AUTH_FACEBOOK_CLIENT_SECRET'), // App Secret
    'redirect' => env('AUTH_FACEBOOK_CLIENT_REDIRECT'),
    ],

    'twitter' => [
    'client_id' => env('AUTH_TWITTER_CLIENT_ID'), // Consumer Key (API Key)
    'client_secret' => env('AUTH_TWITTER_CLIENT_SECRET'), // Consumer Secret (API Secret)
    'redirect' => env('AUTH_TWITTER_CLIENT_REDIRECT'),
    ],

    'google' => [
    'client_id' => env('AUTH_GOOGLE_CLIENT_ID'), // Client ID
    'client_secret' => env('AUTH_GOOGLE_CLIENT_SECRET'), // Client secret
    'redirect' => env('AUTH_GOOGLE_CLIENT_REDIRECT'),
    ],

    3) Make a request from your client to get the oauth info. Each Social provider returns different response and keys

    For testing purposes Apiato provides a web endpoint (http://apiato.test/auth/{provider} ) to act as a client.

    Use that endpoint from your browser (replace the provider with any of the supported providers facebook, twitter,..) to get the oauth info.

    Example Twitter Response:

    User {
    tokentoken: "121212121-121212121"
    tokentokenSecret: "34343434343434343343434343"
    tokenid: "777777777"
    tokennickname: "Mahmoud_Zalt"
    tokenname: "Mahmoud Zalt"
    tokenemail: null
    tokenavatar: "http://pbs.twimg.com/profile_images/88888888/PENrcePC_normal.jpg"
    tokenuser:
    token"avatar_original": "http://pbs.twimg.com/profile_images/9999999/PENrcePC.jpg"
    }

    NOTE: This step should be done by your client App, which could be a Web, Mobile or other kind of client Apps.

    4) Use the oauth info to make a call from your server to the Social Provider in order to get the User info.

    Example Getting Twitter User: Twitter requires the oauth_token and oauth_secret, other Providers might only require the oauth_token

    POST /v1/auth/twitter HTTP/1.1
    Host: api.apiato.test
    Content-Type: application/x-www-form-urlencoded
    Accept: application/json

    oauth_token=121212121-121212121&oauth_secret=34343434343434343343434343

    Note: For Facebook only send oauth_token which is named as access_token in facebook response. For more details about parameters checkout the generated documentation or visit app/Containers/Socialauth/UI/API/Routes/AuthenticateAll.v1.private.php

    5) The endpoint above should return the User and his Personal Access Token.

    Example Twitter Response:

    {
    "data": {
    "object": "User",
    "id": "eqwja3vw94kzmxr0",
    "name": "Mahmoud Zalt",
    "email": null,
    "confirmed": false,
    "nickname": null,
    "gender": null,
    "birth": null,
    "social_auth_provider": "twitter",
    "social_id": "42719726",
    "social_avatar": {
    "avatar": "http://pbs.twimg.com/profile_images/1111111111/PENrcePC_normal.jpg",
    "original": null
    },
    "created_at": {
    "date": "2017-10-20 21:45:03.000000",
    "timezone_type": 3,
    "timezone": "UTC"
    },
    "updated_at": {
    "date": "2017-10-20 21:45:03.000000",
    "timezone_type": 3,
    "timezone": "UTC"
    },
    "readable_created_at": "48 minutes ago",
    "readable_updated_at": "48 minutes ago"
    },
    "meta": {
    "include": [
    "roles"
    ],
    "custom": {
    "token_type": "personal",
    "access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI..."
    }
    }
    }

    Support new Auth Provider

    1) Pick an Auth Provider from the supported providers by Socialite.

    2) Go to app/Containers/Socialauth/Tasks/FindUserSocialProfileTask.php and support your provider.

    - + \ No newline at end of file diff --git a/docs/9.x/core-features/system-settings/index.html b/docs/9.x/core-features/system-settings/index.html index 01c46ea99..dcbe295e9 100644 --- a/docs/9.x/core-features/system-settings/index.html +++ b/docs/9.x/core-features/system-settings/index.html @@ -4,13 +4,13 @@ System Settings | Apiato - +
    Version: 9.x

    System Settings

    At many cases you need to have some dynamic system settings, such as in a referral program, where you give 'gifts' to anyone who refers new users but, those gifts can be changed in the future, so it's better not have them statically created in the code, instead read from the database where an Admin can manage them at any time.

    app/Containers/Settings Container helps to store and retrieve those key values settings. It also seeds the database with the default configurations during the installation.

    Seed the default settings

    Default Settings should be seeded in app/Containers/Settings/Database/Seeders/DefaultSystemSettingsSeeder.php

    Read settings

    <?php
    $value = $this->findSettingsByKeyTask->run('whateverSettingsName');

    You can search for settings by Key as in the example above, or create a class for each settings as follows:

    <?php
    $value = $this->findWhateverSettingsTask->run();
    - + \ No newline at end of file diff --git a/docs/9.x/core-features/useful-commands/index.html b/docs/9.x/core-features/useful-commands/index.html index b6fb90d54..9261fb9a6 100644 --- a/docs/9.x/core-features/useful-commands/index.html +++ b/docs/9.x/core-features/useful-commands/index.html @@ -4,7 +4,7 @@ Useful Commands | Apiato - + @@ -16,7 +16,7 @@ php artisan apiato:list:tasks

    You can also pass --withfilename flag to see all Tasks with the files names. apiato:list:tasks --withfilename

    List Container Dependencies Command

    Sometimes it is required to show dependencies between containers (e.g., how they are interlinked amongst each others). Apiato provides a command to list all dependencies for one specific container. The command does take the Apiato::call() and $this->call() (with use X) into account.

    If you want to get the dependencies for one container, you can call

    php artisan apiato:list:dependencies app/Containers/{container-name}

    - + \ No newline at end of file diff --git a/docs/9.x/core-features/user-registration/index.html b/docs/9.x/core-features/user-registration/index.html index 2c0a4820a..f630ea462 100644 --- a/docs/9.x/core-features/user-registration/index.html +++ b/docs/9.x/core-features/user-registration/index.html @@ -4,13 +4,13 @@ User Registration | Apiato - +
    Version: 9.x

    User Registration

    Register users by credentials (email and passwords)

    Call the http://api.apiato.test/v1/register endpoint (you can find its documentation after generating the API Docs.

    Check out the registerUser endpoint in the API Routes files.

    This will register a new User and respond with user object.

    Registration request:

    curl --request POST \
    --url http://api.apiato.test/v1/register \
    --header 'accept: application/json' \
    --header 'content-type: application/x-www-form-urlencoded' \
    --data 'email=apiato%40mail.com1&password=password&name=Mahmoud%20Zalt'

    Registration response:

    {
    "data": {
    "object": "User",
    "id": XbPW7awNkzl83LD6,
    "name": "Mahmoud Zalt",
    "email": "apiato@mail.com",
    "confirmed": null,
    "nickname": "Mega",
    "gender": "male",
    "birth": null,
    "social_auth_provider": null,
    "social_id": null,
    "social_avatar": {
    "avatar": null,
    "original": null
    },
    "created_at": "2021-03-24T15:02:56.000000Z",
    "updated_at": "2021-03-24T15:02:56.000000Z",
    "readable_created_at": "19 seconds ago",
    "readable_updated_at": "19 seconds ago"
    "roles": {
    "data": []
    }
    }
    }

    Note: After registration in order to get the user access token you will have to send another call to http://api.example.com/v1/oauth/token with following fields and values

    username => your_username e.g. admin@admin.com
    password => your_password
    grant_type => password
    client_id => your_client_id
    client_secret => your_client_secret

    For Third-Party Clients you must have client ID and secret first. You can generate them by creating new client in your app using Laravel Passport.

    For First-Party Clients you can use a proxy to add those fields on requests coming from your trusted client. For an example on how to do it look at ProxyLoginForAdminWebClientAction Action in Authentication Container.

    Register users by Social Account

    (Facebook, Twitter, Google..)

    Checkout the Social Authentication Page for how to Sign up with Social Account.

    - + \ No newline at end of file diff --git a/docs/9.x/core-features/validation/index.html b/docs/9.x/core-features/validation/index.html index bdcafa07d..d2f0ffd96 100644 --- a/docs/9.x/core-features/validation/index.html +++ b/docs/9.x/core-features/validation/index.html @@ -4,13 +4,13 @@ Validation | Apiato - +
    Version: 9.x

    Validation

    Apiato uses the powerful Laravel validation system.

    In Apiato, validation must be defined in Request component, since every request might have different rules.

    Validation rules are automatically applied, once injecting the Request in the Controller.

    Requests help validating User data, accessibility, ownership and more can be added if needed.

    Example Request with Validation rules:

    <?php

    namespace App\Containers\User\UI\API\Requests;

    use App\Ship\Parents\Requests\Request;

    class RegisterUserRequest extends Request
    {
    /**
    * @return array
    */
    public function rules()
    {
    return [
    'email' => 'required|email|max:200|unique:users,email',
    'password' => 'required|min:20|max:300',
    'name' => 'required|min:2|max:400',
    ];
    }

    }

    Usage from Controller Example:

        public function registerUser(RegisterUserRequest $request, CreateUserAction $action)
    {
    // if the actions takes the request object, you can pass the entire request instance as parameter
    $user = Apiato::call('User@RegisterUserAction', [
    [
    $request['email'],
    $request['password'],
    $request['name'],
    $request['gender'],
    $request['birth']
    ]
    ]);

    return $this->transform($user, UserTransformer::class);
    }

    Responses

    Validation Error response format:

    Single Field:

    {
    "errors": {
    "email": [
    "The email has already been taken."
    ]
    },
    "status_code": 422,
    "message": "The given data failed to pass validation."
    }

    Multiple Fields:

    {
    "errors": {
    "email": [
    "The email field is required."
    ],
    "password": [
    "The password field is required."
    ]
    },
    "status_code": 422,
    "message": "The given data failed to pass validation."
    }

    More details about requests in the Requests Page.

    - + \ No newline at end of file diff --git a/docs/9.x/faq/index.html b/docs/9.x/faq/index.html index 2bf274a6c..478b0fd2e 100644 --- a/docs/9.x/faq/index.html +++ b/docs/9.x/faq/index.html @@ -4,7 +4,7 @@ Frequently Asked Questions | Apiato - + @@ -60,7 +60,7 @@ Slack.

    Lastly, if you got your question answered, consider sharing it, if you believe it can help others. You can submit a PR adding the questions and answer here on the FAQ page. Or leave it somewhere on the repository or on Slack. Thanks in advance :)

    - + \ No newline at end of file diff --git a/docs/9.x/getting-started/conventions-and-principles/index.html b/docs/9.x/getting-started/conventions-and-principles/index.html index 5067c28d4..d8aec8478 100644 --- a/docs/9.x/getting-started/conventions-and-principles/index.html +++ b/docs/9.x/getting-started/conventions-and-principles/index.html @@ -4,13 +4,13 @@ Conventions and Principles | Apiato - +
    Version: 9.x

    Conventions and Principles

    HTTP Methods usage in RESTful API's

    • GET (SELECT): retrieve a specific resource from the server, or a listing of resources.
    • POST (CREATE): create a new resource on the server.
    • PUT (UPDATE): update a resource on the server, providing the entire resource.
    • PATCH (UPDATE): update a resource on the server, providing only changed attributes.
    • DELETE (DELETE): remove a resource from the server.

    Naming Conventions for Routes & Actions

    • GetAllResource: to fetch all resources. You can apply ?search query parameter to filter data.
    • FindResourceByID: to search for single resource by its unique identifier.
    • CreateResource: to create a new resource.
    • UpdateResource: to update/edit existing resource.
    • DeleteResource: to delete a resource.

    General guidelines and principles for RESTful URLs

    • A URL identifies a resource.
    • URLs should include nouns, not verbs.
    • Use plural nouns only for consistency (no singular nouns).
    • Use HTTP verbs (GET, POST, PUT, DELETE) to operate on the collections and elements.
    • You should not need to go deeper than resource/identifier/resource.
    • Put the version number at the base of your URL, for example http://apiato.test/v1/path/to/resource.
    • If an input data changes the logic of the endpoint, it should be passed in the URL. If not can go in the header "like Auth Token".
    • Don't use query parameters to alter state.
    • Don't use mixed-case paths if you can help it; lowercase is best.
    • Don't use implementation-specific extensions in your URIs (.php, .py, .pl, etc.)
    • Limit your URI space as much as possible. And keep path segments short.
    • Don't put metadata in the body of a response that should be in a header

    Good URL examples

    • Find a single Car by its unique identifier (ID):
      • GET http://www.api.apiato.test/v1/cars/123
    • Get all Cars:
      • GET http://www.api.apiato.test/v1/cars
    • Find/Search cars by one or more fields:
      • GET http://www.api.apiato.test/v1/cars?search=maker:mercedes
      • GET http://www.api.apiato.test/v1/cars?search=maker:mercedes;color:white
    • Order and Sort query result:
      • GET http://www.api.apiato.test/v1/cars?orderBy=created_at&sortedBy=desc
      • GET http://www.api.apiato.test/v1/cars?search=maker:mercedes&orderBy=created_at&sortedBy=desc
    • Specify optional fields:
      • GET http://www.api.apiato.test/v1/cars?filter=id;name;status
      • GET http://www.api.apiato.test/v1/cars/123?filter=id;name;status
    • Get all Drivers belonging to a Car:
      • GET http://www.api.apiato.test/v1/cars/123/drivers
      • GET http://www.api.apiato.test/v1/cars/123/drivers/123/addresses
    • Include Drivers objects relationship with the car response:
      • GET http://www.api.apiato.test/v1/cars/123?include=drivers
      • GET http://www.api.apiato.test/v1/cars/123?include=drivers,owner
    • Add new Car:
      • POST http://www.api.apiato.test/v1/cars
    • Add new Driver to a Car:
      • POST http://www.api.apiato.test/v1/cars/123/drivers

    General principles for HTTP methods

    • Don't ever use GET to alter state; to prevent Googlebot from corrupting your data. And use GET as much as possible.
    • Don't use PUT unless you are updating an entire resource. And unless you can also legitimately do a GET on the same URI.
    • Don't use POST to retrieve information that is long-lived or that might be reasonable to cache.
    • Don't perform an operation that is not idempotent with PUT.
    • Use GET for things like calculations, unless your input is large, in which case use POST.
    • Use POST in preference to PUT when in doubt.
    • Use POST whenever you have to do something that feels RPC-like.
    • Use PUT for classes of resources that are larger or hierarchical.
    • Use DELETE in preference to POST to remove resources.
    - + \ No newline at end of file diff --git a/docs/9.x/getting-started/installation/index.html b/docs/9.x/getting-started/installation/index.html index ed45a49e4..95faaea23 100644 --- a/docs/9.x/getting-started/installation/index.html +++ b/docs/9.x/getting-started/installation/index.html @@ -4,7 +4,7 @@ Installation | Apiato - + @@ -34,7 +34,7 @@ try running this command homestead halt && homestead up --provision.

    A.3) Using anything else

    If you're not into virtualization solutions, you can set up your environment directly on your machine. Check the software's requirements list.

    C) Let's Play

    Now let's see it in action

    1.a. Open your web browser and visit:

    • http://apiato.test You should see an HTML page, with Apiato in the middle.
    • http://admin.apiato.test You should see an HTML Login page.

    1.b. Open your HTTP client and call:

    • http://api.apiato.test/ You should see a JSON response with message: "Welcome to apiato.",
    • http://api.apiato.test/v1 You should see a JSON response with message: "Welcome to apiato (API V1).",

    2) Make some HTTP calls to the API:

    To make the calls you can use Postman, HTTPIE or any other tool you prefer.

    Let's test the (user registration) endpoint http://api.apiato.test/v1/register with cURL:

    curl -X POST -H "Accept: application/json" -H "Cache-Control: no-cache" -F "email=mahmoud@zalt.me" -F "password=so-secret" -F "name=Mahmoud Zalt" "http://api.apiato.test/v1/register"

    You should get response like this:

    Access-Control-Allow-Origin → ...
    Cache-Control → ...
    Connection → keep-alive
    Content-Language → en
    Content-Type → application/json
    Date → Wed, 11 Apr 2000 22:55:88 GMT
    Server → nginx
    Transfer-Encoding → chunked
    Vary → Origin
    X-Powered-By → PHP/7.7.7
    X-RateLimit-Limit → 30
    X-RateLimit-Remaining → 29

    {
    "data": {
    "object": "User",
    "id": 77,
    "name": "Mahmoud Zalt",
    "email": "apiato@mail.com",
    "confirmed": null,
    "nickname": "Mega",
    "gender": "male",
    "birth": null,
    "social_auth_provider": null,
    "social_id": null,
    "social_avatar": {
    "avatar": null,
    "original": null
    },
    "created_at": {
    "date": "2017-04-05 16:17:26.000000",
    "timezone_type": 3,
    "timezone": "UTC"
    },
    "updated_at": {
    "date": "2017-04-05 16:17:26.000000",
    "timezone_type": 3,
    "timezone": "UTC"
    },
    "roles": {
    "data": []
    }
    }
    }
    - + \ No newline at end of file diff --git a/docs/9.x/getting-started/markdown-features/index.html b/docs/9.x/getting-started/markdown-features/index.html index 41cd3ca51..5cee68210 100644 --- a/docs/9.x/getting-started/markdown-features/index.html +++ b/docs/9.x/getting-started/markdown-features/index.html @@ -4,13 +4,13 @@ Markdown Features | Apiato - +
    Version: 9.x

    Markdown Features

    Docusaurus supports the Markdown syntax and has some additional features.

    Front Matter

    Markdown documents can have associated metadata at the top called Front Matter:

    ---
    id: my-doc
    title: My document title
    description: My document description
    sidebar_label: My doc
    ---

    Markdown content

    Regular Markdown links are supported using url paths or relative file paths.

    Let's see how to [Create a page].
    Let's see how to [Create a page].

    Let's see how to [Create a page].

    Markdown images

    Regular Markdown images are supported.

    Add an image at static/img/logo.png and use this Markdown declaration:

    ![Docusaurus logo](/img/logo.png)

    Docusaurus logo

    Code Blocks

    Markdown code blocks are supported with Syntax highlighting.

    ```jsx title="src/components/HelloDocusaurus.js"
    function HelloDocusaurus() {
    return (
    <h1>Hello, Docusaurus!</h1>
    )
    }
    ```
    src/components/HelloDocusaurus.js
    function HelloDocusaurus() {
    return <h1>Hello, Docusaurus!</h1>;
    }

    Admonitions

    Docusaurus has a special syntax to create admonitions and callouts:

    :::tip My tip

    Use this awesome feature option

    :::

    :::danger Take care

    This action is dangerous

    :::
    My tip

    Use this awesome feature option

    Take care

    This action is dangerous

    React components

    Thanks to MDX, you can make your doc more interactive and use React components inside Markdown:

    export const Highlight = ({children, color}) => (
    <span
    style={{
    backgroundColor: color,
    borderRadius: '2px',
    color: 'red',
    padding: '0.2rem',
    }}>
    {children}
    </span>
    );

    <Highlight color="#25c2a0">Docusaurus green</Highlight> and <Highlight color="#1877F2">Facebook blue</Highlight> are my favorite colors.
    Docusaurus green and Facebook blue are my favorite colors.
    - + \ No newline at end of file diff --git a/docs/9.x/getting-started/overview/index.html b/docs/9.x/getting-started/overview/index.html index 983f0bb30..6ee8305d7 100644 --- a/docs/9.x/getting-started/overview/index.html +++ b/docs/9.x/getting-started/overview/index.html @@ -4,7 +4,7 @@ Overview | Apiato - + @@ -12,7 +12,7 @@
    Version: 9.x

    Overview

    The basic flow

    When an HTTP request is received, it first hits your predefined Endpoint (each endpoint live in its own Route file).

    Sample Route Endpoint

    <?php
    $router->get('hello', [
    'uses' => 'Controller@sayHello',
    ]);

    After the user makes a request to the endpoint [GET] www.api.apiato.com/v1/hello it calls the defined controller function (sayHello).

    Sample Controller Function

    <?php
    class Controller extends ApiController
    {
    public function sayHello(SayHelloRequest $request)
    {
    $helloMessage = Apiato::call(SayHelloAction::class);

    $this->json([
    $helloMessage
    ]);
    }
    }

    This function takes a Request class SayHelloRequest to automatically checks if the user has the right access to this endpoint. Only if the user has access, it proceeds to the function body.

    Then the function calls an Action (SayHelloAction) to perform the business logic.

    Sample Action

    <?php
    class SayHelloAction extends Action
    {
    public function run()
    {
    return 'Hello World!';
    }
    }

    The Action can do anything then return a result (could be an Object, a String or anything).

    When the Action finishes its job, the controller function gets ready to build a response.

    Json responses can be built using the helper function json ($this->json(['foo' => 'bar']);).

    Sample User Response

    [
    "Hello World!"
    ]
    - + \ No newline at end of file diff --git a/docs/9.x/getting-started/requests/index.html b/docs/9.x/getting-started/requests/index.html index 1a346929b..dc5b39a70 100644 --- a/docs/9.x/getting-started/requests/index.html +++ b/docs/9.x/getting-started/requests/index.html @@ -4,7 +4,7 @@ Requests | Apiato - + @@ -17,7 +17,7 @@ you can force your users to send application/json by setting 'force-accept-header' => true, in app/Ship/Configs/apiato.php or allow them to skip it completely by setting the 'force-accept-header' => false,. By default this flag is set to false.

    Calling Endpoints

    Calling unprotected endpoint example:

    curl -X POST -H "Accept: application/json" -H "Content-Type: application/x-www-form-urlencoded; -F "email=admin@admin.com" -F "password=admin" -F "=" "http://api.domain.test/v2/register"

    Calling protected endpoint (passing Bearer Token) example:

    curl -X GET -H "Accept: application/json" -H "Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9..." -H "http://api.domain.test/v1/users"
    - + \ No newline at end of file diff --git a/docs/9.x/getting-started/responses/index.html b/docs/9.x/getting-started/responses/index.html index 4f1eda22a..5dce97880 100644 --- a/docs/9.x/getting-started/responses/index.html +++ b/docs/9.x/getting-started/responses/index.html @@ -4,7 +4,7 @@ Responses | Apiato - + @@ -18,7 +18,7 @@ the App\Containers\User\Models\User::class is User.

    For DataArraySerializer.

    By default, the object keyword is used as a resource key for each response, and it's set manually in each transformer, to be automated later.

    Error Responses formats

    Visit each feature, example the Authentication and there you will see how an unauthenticated response looks like, same for Authorization, Validation and so on.

    Building a Responses from the Controller:

    Checkout the Controller response builder helper functions.

    - + \ No newline at end of file diff --git a/docs/9.x/getting-started/software-architectural-patterns/index.html b/docs/9.x/getting-started/software-architectural-patterns/index.html index c90da30d6..8fbbd37b3 100644 --- a/docs/9.x/getting-started/software-architectural-patterns/index.html +++ b/docs/9.x/getting-started/software-architectural-patterns/index.html @@ -4,7 +4,7 @@ Software Architectural Patterns | Apiato - + @@ -41,7 +41,7 @@ app/Containers/Application/Data/Migrations/.

    10) Create Seeds

    In Laravel, the Seeds files live in the database/migrations/ folder on the root of the project. In Apiato MVC, the Seeds files can live in that same directory or/and in this container folder app/Containers/Application/Data/Seeders/.

    More Classes

    All other classes types work the same way, you can refer to the documentation for where to place them and what they should extend. For more details you can always get in touch with us on Slack.

    How to use Apiato features

    Apiato features are all provided as Actions & Tasks classes.

    • Each Action class has single function run which does one feature only.
    • Each Task class has single function run which does one job only (a tiny piece of the business logic).

    You can use Actions/Tasks classes anyway you want:

    • Using Apiato Facade with Apiato caller style $user = \Apiato::call('Car@GetDriversAction', [$request->id]);
    • Using Apiato Facade with full class name $user = \Apiato::call(GetDriversAction::class, [$request->id]);
    • Using the helper call function with full class name $user = $this->call(GetDriversAction::class, [$request->id]);
    • Using the helper call function with Apiato caller style $user = $this->call('Car@GetDriversAction', [$request->id]);
    • Without Apiato involvement using plain PHP $user = $action = new GetDriversAction::class; $action->run($request->id);
    • Without Apiato involvement using plain Laravel IoC $user = \App::make(GetDriversAction::class)->run($request->id);

    Be creative, at the end of the day it's a class with a function.

    - + \ No newline at end of file diff --git a/docs/9.x/index.html b/docs/9.x/index.html index 0cde92589..e0a246c34 100644 --- a/docs/9.x/index.html +++ b/docs/9.x/index.html @@ -4,13 +4,13 @@ Requirements | Apiato - +
    Version: 9.x

    Requirements

    Requirements

    • GIT
    • PHP >= 7.2 (7.4 is recommended)
    • PHP Extensions:
      • OpenSSL PHP Extension
      • PDO PHP Extension
      • Mbstring PHP Extension
      • Tokenizer PHP Extension
      • BCMath PHP Extension (required when the Hash ID feature is enabled)
      • Intl Extension (required when you use the Localization Container)
    • Composer
    • Node (required for the API Docs generator feature)
    • Web Server (example: Nginx)
    • Cache Engine (example: Redis)
    • Database Engine (example: MySQL)
    • Queues Engine (example: Beanstalkd)
    - + \ No newline at end of file diff --git a/docs/9.x/main-components/actions/index.html b/docs/9.x/main-components/actions/index.html index f4d2f7153..5cb0abfef 100644 --- a/docs/9.x/main-components/actions/index.html +++ b/docs/9.x/main-components/actions/index.html @@ -4,14 +4,14 @@ Actions | Apiato - +
    Version: 9.x

    Actions

    Definition & Principles

    Read the section in the Porto SAP Documentation (#Actions).

    Rules

    • All Actions MUST extend App\Ship\Parents\Actions\Action.

    Folder Structure

     - app
    - Containers
    - {container-name}
    - Actions
    - CreateUserAction.php
    - DeleteUserAction.php
    - ...

    Code Sample

    Delete User Action:

    <?php

    namespace App\Containers\User\Actions;

    use Apiato\Core\Foundation\Facades\Apiato;
    use App\Containers\User\Models\User;
    use App\Ship\Parents\Actions\Action;

    class CreateAdminAction extends Action
    {

    /**
    * @param string $email
    * @param string $password
    * @param string $name
    * @param bool $isClient
    *
    * @return \App\Containers\User\Models\User
    */
    public function run(string $email, string $password, string $name, bool $isClient = false): User
    {
    $admin = Apiato::call('User@CreateUserByCredentialsTask', [
    $isClient,
    $email,
    $password,
    $name
    ]);

    Apiato::call('Authorization@AssignUserToRoleTask', [$admin, ['admin']]);

    return $admin;
    }
    }

    Note: instead of passing these parameters string $email, string $password, string $name, bool $isClient = false from place to another over and over. Consider using the Transporters classes (simple DTO's "Data Transfer Objects"), for more details read the Transporters Page.

    Injecting each Task in constructor and then using it below through its property is really boring, and the more Tasks you use the worse it gets. So instead you can use the function call to call whichever Task you want and then pass any parameters to it.

    The Action itself was also called using Apiato::call() which triggers the run function in it.

    Refer to the Magical Call page for more info and examples on how to use the call function.

    Same Example using the call function:

    <?php

    namespace App\Containers\User\Actions;

    use App\Containers\User\Tasks\DeleteUserTask;
    use App\Ship\Parents\Actions\Action;

    class DeleteUserAction extends Action
    {

    public function run($userId)
    {
    return Apiato::call(DeleteUserTask::class, [$userId]); // <<<<<
    }

    }

    Example: Calling multiple Tasks:

    <?php

    namespace App\Containers\Email\Actions;

    use App\Containers\Xxx\Tasks\Sample111Task;
    use App\Containers\Xxx\Tasks\Sample222Task;
    use App\Ship\Parents\Actions\Action;

    class DemoAction extends Action
    {

    public function run($xxx, $yyy, $zzz)
    {

    $foo = Apiato::call(Sample111Task::class, [$xxx, $yyy]);

    $bar = Apiato::call(Sample222Task::class, [$zzz]);

    // ...

    }

    }

    Action usage from a Controller:

     <?php
    //...

    public function deleteUser(DeleteUserRequest $request)
    {
    $user = Apiato::call(DeleteUserAction::class, [$request->xxx, $request->yyy]);

    return $this->deleted($user);
    }

    //...

    The same Action MAY be called by multiple Controllers (Web, Api, Cli).

    - + \ No newline at end of file diff --git a/docs/9.x/main-components/controllers/index.html b/docs/9.x/main-components/controllers/index.html index a748bb4f8..474c800e3 100644 --- a/docs/9.x/main-components/controllers/index.html +++ b/docs/9.x/main-components/controllers/index.html @@ -4,7 +4,7 @@ Controllers | Apiato - + @@ -13,7 +13,7 @@ This is the most useful function which you will be using in most cases.

    • First required parameter accepts data as object or Collection of objects.
    • Second required parameter is the transformer object
    • Third optional parameter take the includes that should be returned by the response, ($availableIncludes and $defaultIncludes in the transformer class).
    • Fourth optional parameter accepts metadata to be injected in the response.
    // $user is a User Object
    return $this->transform($user, UserTransformer::class);

    // $orders is a Collection of Order Objects
    return $this->transform($orders, OrderTransformer::class, ['products', 'recipients', 'store', 'invoice']);

    withMeta This function allows including metadata in the response.

    $metaData = ['total_credits', 10000];

    return $this->withMeta($metaData)->transform($receipt, ReceiptTransformer::class);

    json This function allows passing array data to be represented as json.

    return $this->json([
    'foo': 'bar'
    ]);

    Other functions

    • accepted
    • deleted
    • noContent
    • // Some functions might not be documented, so refer to the vendor/apiato/core/Traits/ResponseTrait.php and see the public functions.
    - + \ No newline at end of file diff --git a/docs/9.x/main-components/models/index.html b/docs/9.x/main-components/models/index.html index be90d3c09..3746797e9 100644 --- a/docs/9.x/main-components/models/index.html +++ b/docs/9.x/main-components/models/index.html @@ -4,13 +4,13 @@ Models | Apiato - +
    Version: 9.x

    Models

    Definition & Principles

    Read from the Porto SAP Documentation (#Models).

    Rules

    • All Models MUST extend from App\Ship\Parents\Models\Model.
    • If the name of a model differs from the Container name you have to set the $container attribute in the repository - more details.

    Folder Structure

     - App
    - Containers
    - {container-name}
    - Models
    - User.php
    - UserId.php
    - ...

    Code Sample

    <?php

    namespace App\Containers\Demo\Models;

    use App\Ship\Parents\Models\Model;

    class Demo extends Model
    {
    protected $table = 'demos';

    protected $fillable = [
    'label',
    'user_id'
    ];

    protected $hidden = [
    'token',
    ];

    protected $casts = [
    'total_credits' => 'float',
    ];

    protected $dates = [
    'created_at',
    'updated_at',
    ];

    public function user()
    {
    return $this->belongsTo(\App\Containes\User\Models\User::class);
    }
    }

    Notice the Demo Model has a relationship with User Model, which lives in another Container.

    Casts

    The casts attribute can be used to parse any of the model's attributes to a specific type. In the code sample below we can cast total_credits to float.

    More information about the applicable cast-types can be found in the laravel eloquent-mutators documentation.

    You can place any dates inside the $dates to parse those automatically.

    - + \ No newline at end of file diff --git a/docs/9.x/main-components/requests/index.html b/docs/9.x/main-components/requests/index.html index e29738571..24d48d0cc 100644 --- a/docs/9.x/main-components/requests/index.html +++ b/docs/9.x/main-components/requests/index.html @@ -4,7 +4,7 @@ Requests | Apiato - + @@ -24,7 +24,7 @@ function.

    This helper, in turn, allows to "redefine" keys in the request for subsequent processing. Consider the following example request:

    {
    "data" : {
    "name" : "John Doe"
    }
    }

    Your Task to process this data, however, requests the field data.name as data.username. You can call the helper like this:

    $request->mapInput([
    'data.name' => 'data.username',
    ]);

    The resulting structure would look like this:

    {
    "data" : {
    "username" : "John Doe"
    }
    }

    Storing Data on the Request

    During the Request life-cycle you may want to store some data on the request object and pass it to other SubActions (or Tasks).

    To store some data on the request use:

    $request->keep(['someKey' => $someValue]);

    To retrieve the data back at any time during the request life-cycle use:

    $someValue = $request->retrieve('someKey')

    Unit Testing for Actions (Request)

    Since we're passing Request objects to Actions. When writing unit tests we need to create fake Request just to pass it to the Action with some fake data.

    // creating
    $request = RegisterUserRequest::injectData($data);

    Example One:

    $data = [
    'email' => 'Mahmoud@test.test',
    'name' => 'Mahmoud',
    'password' => 'so-secret',
    ];

    // create request object with some data
    $request = RegisterUserRequest::injectData($data);

    // create instance of the Action
    $action = App::make(RegisterUserAction::class)->run($request);

    // do any kind of assertions..
    $this->assertInstanceOf(User::class, $user);

    // ...

    Example Two (With Authenticated User):

    $data = [
    'store_id' => $this->encode($store->id),
    'items' => $orderItems,
    'recipient' => $receipient,
    ];

    $user = factory(User::class)->create();

    $request = MakeOrderRequest::injectData($data, $user);

    $order = App::make(MakeOrderAction::class)->run($request);

    // ...

    - + \ No newline at end of file diff --git a/docs/9.x/main-components/routes/index.html b/docs/9.x/main-components/routes/index.html index f8bf5cf57..a238eea16 100644 --- a/docs/9.x/main-components/routes/index.html +++ b/docs/9.x/main-components/routes/index.html @@ -4,13 +4,13 @@ Routes | Apiato - +
    Version: 9.x

    Routes

    Definition & Principles

    Read from the Porto SAP Documentation (#Routes).

    Rules

    • API Route files MUST be named according to their API's versions, exposure and functionality. Example CreateOrder.v1.public.php, FulfillOrder.v2.public.php, CancelOrder.v1.private.php...

    • Web Route files are pretty similar to API web files, but they can be named anything.

    Folder Structure

     - app
    - Containers
    - {container-name}
    - UI
    - API
    - Routes
    - CreateItem.v1.public.php
    - DeleteItem.v1.public.php
    - CreateItem.v2.public.php
    - DeleteItem.v1.private.php
    - ApproveItem.v1.private.php
    - ...
    - WEB
    - Routes
    - main.php
    - ...

    Web Routes

    Example: Endpoint to display a Hello View in the browser

    <?php

    $router->get('/hello', [
    'uses' => 'Controller@sayHello',
    ]);

    In all the Web Routes files the $router variable is an instance of the default Laravel Router Illuminate\Routing\Router.

    API Routes

    Example: User Login API Endpoint

    <?php

    $router->post('login', [
    'uses' => 'Controller@loginUser',
    ]);

    Example: Protected List All Users API Endpoint, for an API Routes file

    <?php

    $router->get('users', [
    'uses' => 'Controller@listAllUsers',
    'middleware' => [
    'api.auth',
    ]
    ]);

    Protect your Endpoints:

    Checkout the Authorization Page.

    Difference between Public & Private routes files

    apiato has 2 types of endpoints, Public (External) mainly for third parties clients, and Private (Internal) for your own Apps. This will help to generate separate documentations for each and keep your internal API private.

    - + \ No newline at end of file diff --git a/docs/9.x/main-components/subactions/index.html b/docs/9.x/main-components/subactions/index.html index f4a25bda2..1b1b8b1f5 100644 --- a/docs/9.x/main-components/subactions/index.html +++ b/docs/9.x/main-components/subactions/index.html @@ -4,13 +4,13 @@ Sub Actions | Apiato - +
    Version: 9.x

    Sub Actions

    Definition & Principles

    Read from the Porto SAP Documentation (#Sub-Actions).

    Rules

    • All SubActions MUST extend from App\Ship\Parents\Actions\SubAction.

    Folder Structure

     - app
    - Containers
    - {container-name}
    - Actions
    - ValidateAddressSubAction.php
    - BuildOrderSubAction.php
    - ...

    Code Sample

    ValidateAddressSubAction User Action:

    <?php

    namespace App\Containers\Shipment\Actions;

    use App\Containers\Recipient\Models\Recipient;
    use App\Containers\Recipient\Tasks\UpdateRecipientTask;
    use App\Containers\Shipment\Tasks\ValidateAddressWithEasyPostTask;
    use App\Containers\Shipment\Tasks\ValidateAddressWithMelissaDataTask;
    use App\Ship\Parents\Actions\SubAction;

    class ValidateAddressSubAction extends SubAction
    {
    public function run(Recipient $recipient)
    {
    $hasValidAddress = true;

    $easyPostResponse = Apiato::call(ValidateAddressWithEasyPostTask::class, [$recipient]);

    ...
    }
    }

    Every feature available for Actions, is also available in SubActions.

    - + \ No newline at end of file diff --git a/docs/9.x/main-components/tasks/index.html b/docs/9.x/main-components/tasks/index.html index 307226ccd..393798365 100644 --- a/docs/9.x/main-components/tasks/index.html +++ b/docs/9.x/main-components/tasks/index.html @@ -4,13 +4,13 @@ Tasks | Apiato - +
    Version: 9.x

    Tasks

    Definition & Principles

    Read from the Porto SAP Documentation (#Tasks).

    Rules

    • All Tasks MUST extend from App\Ship\Parents\Tasks\Task.

    Folder Structure

     - app
    - Containers
    - {container-name}
    - Tasks
    - ConfirmUserEmailTask.php
    - GenerateEmailConfirmationUrlTask.php
    - SendConfirmationEmailTask.php
    - ValidateConfirmationCodeTask.php
    - SetUserEmailTask.php
    - ...

    Code Sample

    Find User Task by ID:

    <?php

    namespace App\Containers\User\Tasks;

    use App\Containers\User\Contracts\UserRepositoryInterface;
    use App\Ship\Parents\Tasks\Task;
    use Exception;

    class FindUserByIdTask extends Task
    {
    private $userRepository;

    public function __construct(UserRepositoryInterface $userRepository)
    {
    $this->userRepository = $userRepository;
    }

    public function run($id)
    {
    try {
    $user = $this->userRepository->find($id);
    } catch (Exception $e) {
    throw new UserNotFoundException();
    }

    return $user;
    }

    }

    Tasks usage from an Action:

    <?php

    namespace App\Containers\Email\Actions;

    use App\Containers\Email\Tasks\ConfirmUserEmailTask;
    use App\Containers\Email\Tasks\ValidateConfirmationCodeTask;
    use App\Containers\User\Tasks\FindUserByIdTask;
    use App\Ship\Parents\Actions\Action;

    class ValidateUserEmailByConfirmationCodeAction extends Action
    {
    private $validateConfirmationCodeTask;

    private $findUserByIdTask;

    private $confirmUserEmailTask;

    public function __construct(
    ValidateConfirmationCodeTask $validateConfirmationCodeTask,
    FindUserByIdTask $findUserByIdTask,
    ConfirmUserEmailTask $confirmUserEmailTask
    ) {
    $this->validateConfirmationCodeTask = $validateConfirmationCodeTask;
    $this->findUserByIdTask = $findUserByIdTask;
    $this->confirmUserEmailTask = $confirmUserEmailTask;
    }

    public function run($userId, $code)
    {
    $this->validateConfirmationCodeTask->run($userId, $code);
    $user = $this->findUserByIdTask->run($userId);
    $this->confirmUserEmailTask->run($user);
    ...
    }
    }

    - + \ No newline at end of file diff --git a/docs/9.x/main-components/transformers/index.html b/docs/9.x/main-components/transformers/index.html index cdf4b2ac1..ece1f462a 100644 --- a/docs/9.x/main-components/transformers/index.html +++ b/docs/9.x/main-components/transformers/index.html @@ -4,13 +4,13 @@ Transformers | Apiato - +
    Version: 9.x

    Transformers

    Definition & Principles

    Read from the Porto SAP Documentation (#Transformers).

    Rules

    • All API responses MUST be formatted via a Transformer.

    • Every Transformer SHOULD extend from App\Ship\Parents\Transformers\Transformer.

    • Each Transformer MUST have a transform() function.

    Folder Structure

     - app
    - Containers
    - {container-name}
    - UI
    - API
    - Transformers
    - UserTransformer.php
    - ...

    Code Samples

    Reward Transformer with Country relation:

    <?php

    namespace App\Containers\Item\UI\API\Transformers;

    use App\Containers\Item\Models\Item;
    use App\Ship\Parents\Transformers\Transformer;

    class ItemTransformer extends Transformer
    {

    protected $availableIncludes = [
    'images',
    ];

    protected $defaultIncludes = [
    'roles',
    ];

    public function transform(Item $item)
    {
    $response = [
    'object' => 'Item',
    'id' => $item->getHashedKey(),
    'name' => $item->name,
    'description' => $item->description,
    'price' => (float)$item->price,
    'weight' => (float)$item->weight,
    'created_at' => $item->created_at,
    'updated_at' => $item->updated_at,
    ];

    // add more or modify data for Admins only
    $response = $this->ifAdmin([
    'real_id' => $user->id,
    'deleted_at' => $user->deleted_at,
    ], $response);

    return $response;
    }

    public function includeImages(Item $item)
    {
    return $this->collection($item->images, new ItemImageTransformer());
    }

    public function includeRoles(User $user)
    {
    return $this->collection($user->roles, new RoleTransformer());
    }
    }

    Usage from Controller (Single Item)

    <?php

    // getting any Model
    $user = $this->getUser();

    // building the response with the transformer of the Model
    $this->response->item($user, new UserTransformer());

    // in case of collection of data
    $this->response->collection($user, new UserTransformer());

    // in case of Array
    $this->response->array([
    'custom_field' => 'whatever',
    'email' => $user->email,
    ]);

    // more options are available

    Usage from Controller (Multiple Items/Collection)

    <?php

    // getting many Models Paginated
    $rewards = $this->getRewards();

    // building the response with the transformer of the Model
    return $this->response->paginator($rewards, new RewardTransformer());

    Relationships (include)

    Loading relationships in Transformer (calling other Transformers):

    This can be done in 2 ways:

    1. By the User, he can specify what relations to return in response.

    2. By the Developer, define what relations to include at run time.

    From Front-end

    You can request data with their relationships directly from the API call using include=tags,user but first the Transformer need to have the availableIncludes defined with their functions like this:

    <?php

    namespace App\Containers\Account\UI\API\Transformers;

    use App\Ship\Parents\Transformers\Transformer;
    use App\Containers\Account\Models\Account;
    use App\Containers\Tag\Transformers\TagTransformer;
    use App\Containers\User\Transformers\UserTransformer;

    class AccountTransformer extends Transformer
    {
    protected $availableIncludes = [
    'tags',
    'user',
    ];

    public function transform(Account $account)
    {
    return [
    'id' => (int)$account->id,
    'url' => $account->url,
    'username' => $account->username,
    'secret' => $account->secret,
    'note' => $account->note,
    ];
    }

    public function includeTags(Account $account)
    {
    // use collection with `multi` relationship
    return $this->collection($account->tags, new TagTransformer());
    }

    public function includeUser(Account $account)
    {
    // use `item` with single relationship
    return $this->item($account->user, new UserTransformer());
    }

    }

    Now to get the Tags with the response when Accounts are requested pass the ?include=tags parameter with the [GET] request.

    To get Tags with User use the comma separator: ?include=tags,user.

    From Back-end

    From the controller you can dynamically set the DefaultInclude using (setDefaultIncludes) anytime you want.

    <?php

    return $this->response->paginator($rewards, (new ProductsTransformer())->setDefaultIncludes(['tags']));

    You need to have includeTags function defined on the transformer. Look at the full examples above.

    If you want to include a relation with every response from this transformer you can define the relation directly in the transformer on ($defaultIncludes)

    <?php

    protected $availableIncludes = [
    'users',
    ];

    protected $defaultIncludes = [
    'tags',
    ];

    // ..

    You need to have includeUser and includeTags functions defined on the transformer. Look at the full examples above.

    Transformer Available helper functions:

    • user() : returns current authenticated user object.

    • ifAdmin($adminResponse, $clientResponse) : merges normal client response with the admin extra or modified results, when current authenticated user is Admin.

    For more information about the Transformers read this.

    - + \ No newline at end of file diff --git a/docs/9.x/main-components/transporters/index.html b/docs/9.x/main-components/transporters/index.html index 66918b5bb..82624d383 100644 --- a/docs/9.x/main-components/transporters/index.html +++ b/docs/9.x/main-components/transporters/index.html @@ -4,7 +4,7 @@ Transporters | Apiato - + @@ -14,7 +14,7 @@ you can call:

    // "simple" access via direct properties
    $name = $transporter->name;

    // complex access via method
    $username = $transporter->getInputByKey('your.nested.username.field');

    Of course, you can also "sanitize" the data, like you would have done in the Request classes by using sanitizeInput(array).

    Finally, if you need to access the original Request object, you can access it via

    $originalRequest = $transporter->request;

    Set Data

    You can set data in many ways

    $dataTransporter = new DataTransporter($request);
    $dataTransporter->bearerToken = $request->bearerToken();

    If the data is defined as required like this on the Transporter:

        protected $schema = [
    'type' => 'object',
    'properties' => [
    'email',
    'password',
    'clientId',
    'clientPassword',
    ],
    'required' => [
    'email',
    'password',
    'clientId',
    'clientPassword',
    ],
    ];

    Then can set data on the Transporter like this:

    $dataTransporter = new ProxyApiLoginTransporter(
    array_merge($request->all(), [
    'clientId' => Config::get('authentication-container.clients.web.admin.id'),
    'clientPassword' => Config::get('authentication-container.clients.web.admin.secret')
    ])
    );

    Set Instance

    Passing Objects does not work!, because the third party package cannot hydrate it. So to pass instances from a place to another on the Transporter object, you can do the following:

    $transporter = new DataTransporter();
    $transporter->setInstance("command_instance", $this);

    Warning: you can set instances, but they do not appear when calling toArray() or other similar functions, since they cannot be hydrated. See below how you can get the instance form the Transporter object.

    Get Instance:

    $console = $data->command_instance;

    Get Data

    To get all data from the Transporter you can call $data->toArray() or $data->toJson()... there are many other functions on the class.

    To get specific data just call the data name, as you would when accessing data from a Request object $data->username.

    - + \ No newline at end of file diff --git a/docs/9.x/main-components/views/index.html b/docs/9.x/main-components/views/index.html index 949e0a858..866def219 100644 --- a/docs/9.x/main-components/views/index.html +++ b/docs/9.x/main-components/views/index.html @@ -4,13 +4,13 @@ Views | Apiato - +
    Version: 9.x

    Views

    Definition & Principles

    Read from the Porto SAP Documentation (#Views).

    Rules

    • Views SHOULD be created inside the Containers, and they will be automatically available for use in the Web Controllers.

    • All Views are namespaced as the lower case of the Container name.

    Folder Structure

     - app
    - Containers
    - {container-name}
    - UI
    - WEB
    - Views
    - welcome.php
    - profile.php
    - ...

    Code Sample

    Welcome page View

    <!DOCTYPE html>
    <html>
    <head>
    <title>Welcome</title>
    </head>
    <body>
    <div class="container">
    <div class="content">
    <div class="title">Welcome</div>
    </div>
    </div>
    </body>
    </html>

    Example: Usage From Controller

    <?php

    namespace App\Containers\Welcome\UI\WEB\Controllers;

    use App\Ship\Parents\Controllers\WebController;

    class Controller extends WebController
    {
    public function sayWelcome()
    {
    return view('just-welcome');
    }
    }

    Namespaces

    By default, all the Container Views are namespaced to the Container name.

    Example:

    If a Container named Store has View say-hello, you can access the view like this view('store::just-welcome'). If you try to access it without the namespace view('just-welcome'), it will not find your View.

    - + \ No newline at end of file diff --git a/docs/9.x/miscellaneous/container-installer/index.html b/docs/9.x/miscellaneous/container-installer/index.html index f309f5817..430309547 100644 --- a/docs/9.x/miscellaneous/container-installer/index.html +++ b/docs/9.x/miscellaneous/container-installer/index.html @@ -4,7 +4,7 @@ Containers Installer | Apiato - + @@ -24,7 +24,7 @@ that allows installing / updating containers.
  • You must provide the key extra.apiato.container.name. This key indicates the name of the folder (e.g., container) when installing the package to the /app/Containers folder. In the shown example, the container would be installed to app/Containers/Foo.
  • - + \ No newline at end of file diff --git a/docs/9.x/miscellaneous/magical-call/index.html b/docs/9.x/miscellaneous/magical-call/index.html index cc6397370..447dd586d 100644 --- a/docs/9.x/miscellaneous/magical-call/index.html +++ b/docs/9.x/miscellaneous/magical-call/index.html @@ -4,7 +4,7 @@ Magical Call | Apiato - + @@ -27,7 +27,7 @@ automatically rolled-back from the database. However, respective operations on the file system (e.g., you may also have uploaded a profile picture for this Team already that needs to be removed in this case) need to be performed manually!

    Typically, you may want to use the transactionalCall() on the Controller level!

    Use case example

    <?php

    return Apiato::call('User@ListUsersTask', [], ['ordered']);
    // can be called this way as well Apiato::call(ListUsersTask::class, [], ['ordered']);

    return Apiato::call('User@ListUsersTask', [], ['ordered', 'clients']);

    return Apiato::call('User@ListUsersTask', [], ['admins']);

    return Apiato::call('User@ListUsersTask', [], ['admins', ['roles' => ['manager', 'employee']]]);

    The ListUsersTask class

    <?php

    namespace App\Containers\User\Tasks;

    use App\Containers\User\Data\Criterias\AdminsCriteria;
    use App\Containers\User\Data\Criterias\ClientsCriteria;
    use App\Containers\User\Data\Criterias\RoleCriteria;
    use App\Containers\User\Data\Repositories\UserRepository;
    use App\Ship\Criterias\Eloquent\OrderByCreationDateDescendingCriteria;
    use App\Ship\Parents\Tasks\Task;

    class ListUsersTask extends Task
    {
    private $userRepository;

    public function __construct(UserRepository $userRepository)
    {
    $this->userRepository = $userRepository;
    }

    public function run()
    {
    return $this->userRepository->paginate();
    }

    public function clients()
    {
    $this->userRepository->pushCriteria(new ClientsCriteria());
    }

    public function admins()
    {
    $this->userRepository->pushCriteria(new AdminsCriteria());
    }

    public function ordered()
    {
    $this->userRepository->pushCriteria(new OrderByCreationDateDescendingCriteria());
    }

    public function withRole($roles)
    {
    $this->userRepository->pushCriteria(new RoleCriteria($roles));
    }

    }

    - + \ No newline at end of file diff --git a/docs/9.x/miscellaneous/postman/index.html b/docs/9.x/miscellaneous/postman/index.html index ce134666c..c71cb3651 100644 --- a/docs/9.x/miscellaneous/postman/index.html +++ b/docs/9.x/miscellaneous/postman/index.html @@ -4,7 +4,7 @@ Postman Environment | Apiato - + @@ -15,7 +15,7 @@ access all routes.

    php artisan migrate:refresh --seed
    php artisan passport:client --password
    php artisan apiato:permissions:toRole admin

    Be sure to copy and paste your new client_id and client_secret into the .env file. Like so...

    CLIENT_WEB_ADMIN_ID={CLIENT_ID}
    CLIENT_WEB_ADMIN_SECRET={CLIENT_SECRET}

    CLIENT_MOBILE_ADMIN_ID={CLIENT_ID}
    CLIENT_MOBILE_ADMIN_SECRET={CLIENT_SECRET}

    The above steps will ensure you have a functioning Apiato API environment to explore with Postman.

    Download & Install Postman

    Visit the Postman website and download the application.

    Download Postman

    Add Apiato Environment & Collection to Postman

    Download Apiato Environment & Collection

    Steps

    • Open Postman
    • Click on "import" button top left of Postman application.
    • Click on "Choose files". Select both the Environment and Collection JSON files and click add.
    • Select "Apiato Environment" from the Environment dropdown list on the top right of the Postman Application.

    Using the Postman Apiato API Collection

    The first thing you need to do to use the Apiato endpoints is to log in to your Apiato API.

    • Select the Apiato API Collection in the left menu.
    • Select Authentication folder.
    • Select Login endpoint.
    • Click Send button.

    The response will return a body with the API access token. Normally you would have to manually add this in a header with each request using Authorization: Bearer TOKEN. This however is automatically done for you.

    From this point you can now access all endpoints using the Super Admin role.

    If you would like to test logging into your application with different users then switch to the body tab on the login endpoint and update the credentials.

    {
    "email": "admin@admin.com",
    "password": "admin"
    }
    - + \ No newline at end of file diff --git a/docs/9.x/miscellaneous/tasks-queuing/index.html b/docs/9.x/miscellaneous/tasks-queuing/index.html index 4c1e19cfc..ba18c1de8 100644 --- a/docs/9.x/miscellaneous/tasks-queuing/index.html +++ b/docs/9.x/miscellaneous/tasks-queuing/index.html @@ -4,7 +4,7 @@ Tasks Queuing | Apiato - + @@ -18,7 +18,7 @@

    More info here (docs).

    The only addition to the Laravel's queues in Apiato, is that by default, apiato detects which queue driver you are planning to use (based on the configs), to create the migration files required, in case type database is used.

    if (Config::get('queue.default') == 'database')
    {
    // do something
    }

    (refer to app/Ship/Migrations/ folder for more details).

    Beanstalkd

    In order to use Beanstalkd as your queue driver, you need to require the "pda/pheanstalk": "^3.1" package first. You can include this in any composer.json file you want.

    - + \ No newline at end of file diff --git a/docs/9.x/miscellaneous/tasks-scheduling/index.html b/docs/9.x/miscellaneous/tasks-scheduling/index.html index 8606a7851..499529425 100644 --- a/docs/9.x/miscellaneous/tasks-scheduling/index.html +++ b/docs/9.x/miscellaneous/tasks-scheduling/index.html @@ -4,7 +4,7 @@ Tasks Scheduling | Apiato - + @@ -18,7 +18,7 @@ See the Commands Page.

    Once you have your command ready, go to app/Ship/Kernels/ConsoleKernel.php and start adding the commands you need to schedule inside the schedule function.

    Example:

    <?php
    protected function schedule(Schedule $schedule)
    {
    $schedule->command('apiato:welcome')->everyMinute();
    $schedule->job(new myJob)->hourly();
    $schedule->exec('touch me.txt')->dailyAt('12:00');
    // ...
    }

    More details here.

    NOTE: you do not need to register the commands with the $commands property or point to them in the commands() function. Apiato will do that automatically for you.

    - + \ No newline at end of file diff --git a/docs/9.x/miscellaneous/tests-helpers/index.html b/docs/9.x/miscellaneous/tests-helpers/index.html index e1b0c4bb8..99572a52e 100644 --- a/docs/9.x/miscellaneous/tests-helpers/index.html +++ b/docs/9.x/miscellaneous/tests-helpers/index.html @@ -4,7 +4,7 @@ Tests Helpers | Apiato - + @@ -25,7 +25,7 @@ testing data.

    1. Go to Seeder/SeedTestingData.php seeder class, and create your live testing data.

    2. Run this command php artisan apiato:seed-test

    Debugging with PsySH

    For better debugging and development, you can open a runtime developer console while executing your test.

    Using PsySH (interactive debugger and REPL "read-eval-print loop" for PHP). The package is required by the Laravel Tinker Package.

    To use it set the breakpoint eval(\Psy\sh()); anywhere you want in any Actions, Controllers, Tasks... and run your test normally.

    - + \ No newline at end of file diff --git a/docs/9.x/optional-components/commands/index.html b/docs/9.x/optional-components/commands/index.html index 78a46e84f..2c5c09b7d 100644 --- a/docs/9.x/optional-components/commands/index.html +++ b/docs/9.x/optional-components/commands/index.html @@ -4,13 +4,13 @@ Commands | Apiato - +
    Version: 9.x

    Commands

    Definition

    Commands:

    • is a laravel artisan command. Laravel has its own default commands, and you create your own as well.
    • provides a way to interact with the Laravel app.
    • a Command can be scheduled by a Task scheduler, like Cron Job or by the Laravel built-in wrapper of the Cron Job "laravel scheduler".
    • Commands could be Closure based or Classes.
    • "dispatch" is the term that is usually used to call a Command.

    Principles

    • Containers MAY or MAY NOT have one or more Commands.

    • Every Command SHOULD call an Action to perform its job, and should not container any business logic.

    • Ship may contain Application general Commands.

    Rules

    • All Commands MUST extend from App\Ship\Parents\Commands\ConsoleCommand.

    Folder Structure

     - app
    - Containers
    - {container-name}
    - UI
    - CLI
    - Commands
    - SayHelloCommand.php
    - ...
    - Ship
    - Commands
    - GeneralCommand.php
    - ...

    Code Samples

    Example: a simple Command

    <?php

    namespace App\Containers\Welcome\UI\CLI\Commands;

    use App\Ship\Parents\Commands\ConsoleCommand;

    /**
    * Class SayWelcomeCommand
    *
    * @author Mahmoud Zalt <mahmoud@zalt.me>
    */
    class SayWelcomeCommand extends ConsoleCommand
    {

    /**
    * The name and signature of the console command.
    *
    * @var string
    */
    protected $signature = 'apiato:welcome';

    /**
    * The console command description.
    *
    * @var string
    */
    protected $description = 'Just saying Welcome.';

    /**
    * Create a new command instance.
    *
    * @return void
    */
    public function __construct()
    {
    parent::__construct();
    }

    /**
    * Execute the console command.
    *
    * @return void
    */
    public function handle()
    {
    $this->info('Welcome to apiato :)'); // green color
    // $this->line('Welcome to apiato :)'); // normal color
    }
    }

    Usage from CLI (Terminal):

    php artisan apiato:welcome

    Schedule Commands Execution

    To Schedule the execution of a Command checkout the Tasks Scheduling page.

    Define Consoles Routes

    To define Console route go to app/Ship/Commands/Routes.php.

    - + \ No newline at end of file diff --git a/docs/9.x/optional-components/configs/index.html b/docs/9.x/optional-components/configs/index.html index 4f60efc12..6451620c3 100644 --- a/docs/9.x/optional-components/configs/index.html +++ b/docs/9.x/optional-components/configs/index.html @@ -4,13 +4,13 @@ Configs | Apiato - +
    Version: 9.x

    Configs

    Definition

    Configs are files that container configurations. For more details about them check this doc.

    In each Apiato container, there are two types of config files:

    • the container specific config file (a config file that contains the container specific configurations).
    • the container third party packages config files (a config file that belongs to a third party package, required by the composer file of the container).

    Principles

    • Your custom config files and third party packages config files, should be placed in the Container, unless it's too generic then it can be placed on the Ship Layer.
    • Container can have as many config files as it needs.

    Rules

    • When publishing a third party package config file move it manually to its container or to the Ship Features Config folder in case it is generic.
    • Framework config files (provided by laravel) lives at the default config directory on the root of the project.
    • You SHOULD NOT add any config file to the config directory.
    • The container specific config file, MUST have the same name of the container in lower letters and post-fixed with -container, to prevent conflicts between third party packages and container specific packages.

    Folder Structure

    - app
    - Containers
    - {container-name}
    - Configs
    - {container-name}-container.php
    - package-config-file1.php
    - ...
    - Ship
    - Configs
    - apiato.php
    - ...
    - config
    - app.php
    - ...

    Code Samples

    Example simple Config file

    <?php
    // app/Containers/{ContainerName}/Configs/{container-name}-container.php
    return [

    /*
    |--------------------------------------------------------------------------
    | Default Namespace
    |--------------------------------------------------------------------------
    */
    'namespace' => 'App',

    // some other config params here...

    You can access the respective configuration key like this:

    $value = Config::get('{container-name}-container.namespace');     // returns 'App'
    $value = config('{container-name}-container.namespace'); // same, but using a function

    $defaultValue = Config::get('{container-name}-container.unknown.key', 'defaultvalue'); // returns 'defaultvalue' as this key is not set!
    - + \ No newline at end of file diff --git a/docs/9.x/optional-components/criterias/index.html b/docs/9.x/optional-components/criterias/index.html index cd29a3a02..e33852db9 100644 --- a/docs/9.x/optional-components/criterias/index.html +++ b/docs/9.x/optional-components/criterias/index.html @@ -4,13 +4,13 @@ Criterias | Apiato - +
    Version: 9.x

    Criterias

    Definition

    Criterias are classes used to hold and apply query condition when retrieving data from the database through a Repository.

    Without using a Criteria class, you can add your query conditions to a Repository or to a Model as scope, but with Criterias, your query conditions can be shared across multiple Models and Repositories. It allows you to define the query condition once and use it anywhere in the App.

    Principles

    • Every Container MAY have its own Criterias. However, shared Criterias SHOULD be created in the Ship layer.

    • A Criteria MUST not contain any extra code, if it needs data, the data SHOULD be passed to it from the Actions or the Task. It SHOULD not run (call) any Task for data.

    Rules

    • All Criterias MUST extend from App\Ship\Parents\Criterias\Criteria.

    • Every Criteria SHOULD have an apply() function.

    • A simple query condition example "where user_id = $id", this can be named "This User Criteria", and used with all Models which have relations with the User Model.

    Folder Structure

     - app
    - Containers
    - {container-name}
    - Data
    - Criterias
    - ColourRedCriteria.php
    - RaceCarsCriteria.php
    - ...
    - Ship
    - Features
    - Criterias
    - Eloquent
    - CreatedTodayCriteria.php
    - NotNullCriteria.php
    - ...

    Code Samples

    Example: a shared Criteria

    <?php

    namespace App\Ship\Features\Criterias\Eloquent;

    use App\Ship\Parents\Criterias\Criteria;
    use Prettus\Repository\Contracts\RepositoryInterface as PrettusRepositoryInterface;

    class OrderByCreationDateDescendingCriteria extends Criteria
    {
    public function apply($model, PrettusRepositoryInterface $repository)
    {
    return $model->orderBy('created_at', 'desc');
    }
    }

    Usage from Task:

    <?php

    public function run()
    {
    $this->userRepository->pushCriteria(new OrderByCreationDateDescendingCriteria);

    $users = $this->userRepository->paginate();

    return $users;
    }

    Example: Criteria accepting data input:

    <?php

    namespace App\Ship\Features\Criterias\Eloquent;

    use App\Ship\Parents\Criterias\Criteria;
    use Prettus\Repository\Contracts\RepositoryInterface as PrettusRepositoryInterface;

    class ThisUserCriteria extends Criteria
    {

    private $userId;

    public function __construct($userId)
    {
    $this->userId = $userId;
    }

    public function apply($model, PrettusRepositoryInterface $repository)
    {
    return $model->where('user_id', '=', $this->userId);
    }
    }

    Example: Passing data from Task to Criteria:

    <?php

    public function run($user)
    {
    $this->accountRepository->pushCriteria(new ThisUserCriteria($user->id));

    $accounts = $this->accountRepository->paginate();

    return $accounts;
    }

    For more information about the Criteria read this.

    - + \ No newline at end of file diff --git a/docs/9.x/optional-components/events/index.html b/docs/9.x/optional-components/events/index.html index 50706bf7c..cfe8b4795 100644 --- a/docs/9.x/optional-components/events/index.html +++ b/docs/9.x/optional-components/events/index.html @@ -4,13 +4,13 @@ Events | Apiato - +
    Version: 9.x

    Events

    Definition

    Events:

    • Events provide a simple observer implementation, allowing you to subscribe and listen for various events that occur in your application.
    • Events are classes that can be fired from anywhere in your application.
    • An event class will usually be bound to one or many Events Listeners Classes or has those Listeners registered to listen to it.
    • "fire" is the term that is usually used to call an Event.

    More details here.

    Principles

    • Events can be fired from Actions and or Tasks. It's preferable to choose one place only. (Tasks are recommended).
    • Events SHOULD be created inside the Containers. However, general Events CAN be created in the Port layer.

    Rules

    • Event classes CAN be placed inside the Containers in Events folders or on the Ship for the general Events.
    • All Events MUST extend from App\Ship\Parents\Events\Event.

    Folder Structure

     - App
    - Containers
    - {container-name}
    - Events
    - SomethingHappenedEvent.php
    - ...
    - Listeners
    - ListenToMusicListener.php
    - ...

    - Ship
    - Events
    - GlobalStateChanged.php
    - SomethingBiiigHappenedEvent.php
    - ...

    Enabling Events

    Before you can use events you need to add the EventServiceProvider to the MainServiceProvider of the Ship (if this has not been registered so far). See example below.

    <?php

    namespace App\Containers\Car\Providers;

    class MainServiceProvider extends MainProvider
    {

    /**
    * Container Service Providers.
    *
    * @var array
    */
    public $serviceProviders = [
    EventServiceProvider::class,
    ];

    // ...
    }

    Usage

    In Laravel, you can create and register events in multiple way. Below is an example of an Event that handles itself.

    Event Class Example:

    <?php

    namespace App\Containers\User\Events;

    use App\Containers\User\Models\User;
    use App\Ship\Parents\Events\Event;
    use Illuminate\Broadcasting\PrivateChannel;
    use Illuminate\Contracts\Queue\ShouldQueue;
    use Illuminate\Support\Facades\Log;

    class UserRegisteredEvent extends Event implements ShouldQueue
    {
    protected $user;

    public function __construct(User $user)
    {
    $this->user = $user;
    }

    public function handle()
    {
    Log::info('New User registration. ID = ' . $this->user->getHashedKey() . ' | Email = ' . $this->user->email . '.');

    // ...
    }

    public function broadcastOn()
    {
    return new PrivateChannel('channel-name');
    }
    }

    Note: You will get more benefits creating Events Listeners for each Event.

    To do this you will need to create a custom EventServiceProvider in your container extending App\Ship\Parents\Providers\EventsProvider.

    Your custom EventServiceProvider needs to be registered in the containers MainServiceProvider as well.

    <?php

    namespace App\Containers\Car\Providers;

    use App\Ship\Parents\Providers\MainProvider;

    /**
    * Class MainServiceProvider.
    *
    * The Main Service Provider of this container, it will be automatically registered in the framework.
    */
    class MainServiceProvider extends MainProvider
    {

    /**
    * Container Service Providers.
    *
    * @var array
    */
    public $serviceProviders = [
    EventServiceProvider::class,
    ];

    Dispatch Events

    You can dispatch an Event from anywhere you want (ideally from Actions and Tasks).

    Example: Dispatching the Event class from the example above

    <?php

    // using helper function
    event(New UserEmailChangedEvent($user));

    // manually
    \App::make(\Illuminate\Contracts\Bus\Dispatcher\Dispatcher::class)->dispatch(New UserEmailChangedEvent($user));

    Queueing an Event

    Events can implement Illuminate\Contracts\Queue\ShouldQueue to be queued.

    Handling an Event

    You can handle jobs on dispatching an event.

    To do so, you need to implement one of the following interfaces:

    Apiato\Core\Abstracts\Events\Interfaces\ShouldHandleNow

    Apiato\Core\Abstracts\Events\Interfaces\ShouldHandle

    This will force you to implement the handle method and will make apiato execute the method upon dispatching the event.

    • The ShouldHandleNow Interface will make the event execute the handle method as soon as the event gets dispatched.

    • The ShouldHandle Interface will create an eventjob and execute the handle method async (through laravel jobs).

    namespace App\Containers\Example\Events;


    use Apiato\Core\Abstracts\Events\Interfaces\ShouldHandle;
    use App\Ship\Parents\Events\Event;

    class ExampleEvent extends Event implements ShouldHandle
    {
    /**
    * If ShouldHandle interface is implemented this variable
    * sets the time (in seconds or timestamp) to wait before a job is executed
    *
    * @var \DateTimeInterface|\DateInterval|int|null $jobDelay
    */
    public $jobDelay = 60;

    /**
    * If ShouldHandle interface is implemented this variable
    * sets the name of the queue to push the job on
    *
    * @var string $jobQueue
    */
    public $jobQueue = "example_queue";

    public function handle()
    {
    // Do some handling here
    }

    }

    Broadcasting

    Note: to define Broadcasting route go to app/Ship/Boardcasts/Routes.php.

    - + \ No newline at end of file diff --git a/docs/9.x/optional-components/exceptions/index.html b/docs/9.x/optional-components/exceptions/index.html index 88a0e8b27..29d82c48a 100644 --- a/docs/9.x/optional-components/exceptions/index.html +++ b/docs/9.x/optional-components/exceptions/index.html @@ -4,13 +4,13 @@ Exceptions | Apiato - +
    Version: 9.x

    Exceptions

    Definition

    Exceptions are classes the handles errors, and helps developers debug their code in a more efficient way.

    Principles

    • Exceptions can be thrown from anywhere in the application.
    • Exceptions SHOULD be created inside the Containers. However, general Exceptions CAN be created in the Ship layer.

    Rules

    • All Exceptions MUST extend App\Ship\Parents\Exceptions\Exception.
    • Shared (general) Exceptions between all Containers SHOULD be created in the Exceptions Ship folder (app/Ship/Exceptions/*).
    • Every Exception SHOULD have two properties httpStatusCode and message, both properties will be displayed when an error occurs. You can override those values while throwing the error.

    Folder Structure

     - App
    - Containers
    - {container-name}
    - Exceptions
    - AccountFailedException.php
    - ...

    - Ship
    - Exceptions
    - IncorrectIdException.php
    - InternalErrorException.php
    - ...

    Code Samples

    User Exception:

    <?php

    namespace App\Containers\User\Exceptions;

    use App\Ship\Parents\Exceptions\Exception;
    use Symfony\Component\HttpFoundation\Response;

    class AccountFailedException extends Exception
    {
    public $httpStatusCode = Response::HTTP_CONFLICT;

    public $message = 'Failed creating new User.';

    public $code = 4711;
    }

    General Exception:

    <?php

    namespace App\Ship\Exceptions;

    use App\Ship\Parents\Exceptions\Exception;
    use Symfony\Component\HttpFoundation\Response as SymfonyResponse;

    class InternalErrorException extends Exception
    {
    public $httpStatusCode = SymfonyResponse::HTTP_INTERNAL_SERVER_ERROR;

    public $message = 'Something went wrong!';
    }

    General Exception with CustomData:

    <?php

    namespace App\Ship\Exceptions;

    use App\Ship\Parents\Exceptions\Exception;
    use Symfony\Component\HttpFoundation\Response as SymfonyResponse;

    class AwesomeExceptionWithCustomData extends Exception
    {
    public $httpStatusCode = SymfonyResponse::HTTP_INTERNAL_SERVER_ERROR;

    public $message = 'Something went wrong!';

    public $code = 1234;

    /*
    * Everything you add here will be automatically added to the ExceptionFormatter on the top level!
    * You can define any structure you want or maybe include translated messages
    */
    public function addCustomData() {
    return [
    'title' => 'nice',
    'description' => 'one fancy description here',
    'foo' => true,
    'meta' => [
    'bar' => 1234,
    ]
    ];
    }
    }

    Exception usage from anywhere:

    <?php

    throw new AccountFailedException();

    Usage with Log for Debugging:

    <?php

    throw (new AccountFailedException())->debug($e); // debug() accepts string or \Exception instance

    Usage and overriding the default message:

    <?php

    throw new AccountFailedException('I am the message to be displayed for the user');

    Usage and overwriting pre-set CustomData

    <?php

    throw (new AwesomeExceptionWithCustomData())->overrideCustomData(['foo' => 'bar']);

    Application Error Codes

    Apiato provides a convenient way to manage all application error codes in one central place. Therefore, Apiato provides, amongst others, the \App\Ship\Exceptions\Codes\ApplicationErrorCodesTable class, which already holds various information for multiple errors.

    Thereby, one error look like this:

    const BASE_GENERAL_ERROR = [
    'code' => 1001,
    'title' => 'Unknown / Unspecified Error.',
    'description' => 'Something unexpected happened.',
    ];

    Note that the code is used to be sent back to the client. The title and description, however, can be used to automatically generate a documentation regarding all defined error codes and their meaning. Please note that this feature is currently not implemented but will be added later on.

    Linking Exceptions and Error Codes

    In order to link an error code to an Exception, you simply need override the useErrorCode() method of the Exception.

    Consider the following example:

    class InternalErrorException extends Exception
    {

    public $httpStatusCode = SymfonyResponse::HTTP_INTERNAL_SERVER_ERROR;

    public $message = 'Something went wrong!';

    public code = 4711; // this code will be overwritten by the useErrorCode() method!

    public function useErrorCode()
    {
    return ApplicationErrorCodes::BASE_INTERNAL_ERROR;
    }
    }

    Please note that already defined $code values may be overwritten by the useErrorCode() method! Furthermore, this feature is completely optional - you may still use the known public $code = 4711; approach to manually set an error code.

    Defining Own Error Code Tables

    Of course, Apiato allows you to define your own CustomErrorCodesTable. In fact, there already exists such a file where you can define your own error codes. Please note that the ApplicationErrorCodesTable may be adapted by Apiato - the others will not.

    If you like to split the errors in various files, you can easily create a UserErrorCodesTable in respective namespace and define the errors accordingly. However, you need to manually "register" this code table. This can be achieved in the ErrorCodeManager::getCodeTables() method.

    Now you can easily use your UserErrorCodesTable::USER_NOT_VERIFIED error in your Exception class.

    - + \ No newline at end of file diff --git a/docs/9.x/optional-components/factories/index.html b/docs/9.x/optional-components/factories/index.html index 1cf62953c..141a95c1c 100644 --- a/docs/9.x/optional-components/factories/index.html +++ b/docs/9.x/optional-components/factories/index.html @@ -4,13 +4,13 @@ Factories | Apiato - +
    Version: 9.x

    Factories

    Definition

    Factories (are a short name for Models Factories).

    Factories are used to generate some fake data with the help of Faker to be used for testing purposes.

    Factories are mainly used from Tests.

    Principles

    • Factories SHOULD be created in the Containers.

    Rules

    • A Factory is just a plain PHP script. (No classes or namespaces required)

    Folder Structure

     - app
    - Containers
    - {container-name}
    - Data
    - Factories
    - UserFactory.php
    - ...

    Code Samples

    A User Model Factory:

    <?php

    // User
    $factory->define(App\Containers\User\Models\User::class, function (Faker\Generator $faker) {
    return [
    'name' => $faker->name,
    'email' => $faker->email,
    'password' => bcrypt(str_random(10)),
    ];
    });

    // ...

    Usage from Tests or anywhere else:

    <?php

    // creating 4 users
    factory(User::class, 4)->create();

    Usage with relationships:

    <?php

    $countries = Country::all();

    // creating 3 rewards and attaching country relation to them
    $rewards = factory(Reward::class, 3)->make()->each(function ($reward) use ($countries) {
    $reward->save();
    $reward->countries()->attach([$countries->random(1)->id, $countries->random(1)->id]);
    $reward->save();
    });

    Use make instance of create and pass any data any way, then save after establishing the relations.

    Usage while overriding some values:

    <?php

    // creating single Offer and setting a user id
    $offer = factory(Offer::class)->make();
    $offer->user_id = $user->id;
    $offer->save();

    // ANOTHER EXAMPLE:

    // creating multiple Accounts
    factory(Account::class, 3)->make()->each(function ($account) use ($user) {
    $account->user_id = $user->id;
    $account->save();
    });

    For more information about the Models Factories read this.

    - + \ No newline at end of file diff --git a/docs/9.x/optional-components/jobs/index.html b/docs/9.x/optional-components/jobs/index.html index 0378f0701..1bf38e571 100644 --- a/docs/9.x/optional-components/jobs/index.html +++ b/docs/9.x/optional-components/jobs/index.html @@ -4,13 +4,13 @@ Jobs | Apiato - +
    Version: 9.x

    Jobs

    Definition

    Jobs:

    • are simple classes that can do one thing or multiple related things.
    • Job is a name given to a class that is usually created to be queued (it's execution is usually deferred for later, after the execution of previous Jobs are completed).
    • Jobs can be scheduled to be executed later by a queuing mechanism (queue system like beanstalkd).
    • When a Job class is dispatched, it performs its specific job and dies.
    • Laravel's queue worker will process every Job as it's pushed onto the queue.

    More info here.

    Principles

    • A Container MAY have more than one Job.

    Rules

    • All Jobs MUST extend from App\Ship\Parents\Jobs\Job.

    Folder Structure

     - app
    - Containers
    - {container-name}
    - Jobs
    - DoSomethingJob.php
    - DoSomethingElseJob.php

    Code Samples

    CreateAndValidateAddress with third party Job:

    <?php

    namespace App\Containers\Shipment\Jobs;

    use App\Port\Job\Abstracts\Job;

    class CreateAndValidateAddressJob extends Job
    {
    private $recipients;

    public function __construct(array $recipients)
    {
    $this->recipients = $recipients;
    }

    public function handle()
    {
    foreach ($this->recipients as $recipient) {
    // do whatever you like
    }
    }
    }

    Check the parent Job class.

    Usage from Action:

    <?php

    // using helper function
    dispatch(new CreateAndValidateAddressJob($recipients));

    // manually
    App::make(\Illuminate\Contracts\Bus\Dispatcher\Dispatcher::class)->dispatch(New StatusChangedJob($object));

    Execute Jobs Execution

    For running your Jobs checkout the Tasks Queuing page.

    - + \ No newline at end of file diff --git a/docs/9.x/optional-components/languages/index.html b/docs/9.x/optional-components/languages/index.html index 10abffe51..5f9bef4ce 100644 --- a/docs/9.x/optional-components/languages/index.html +++ b/docs/9.x/optional-components/languages/index.html @@ -4,13 +4,13 @@ Languages | Apiato - +
    Version: 9.x

    Languages

    Definition

    Languages are not real Components, they are just files that holds translations.

    Rules

    • Languages CAN be placed inside the Containers. However, the default laravel resources/lang languages files are still loaded and can be used as well.

    • All Translations are namespaced as the lower case of the Container name.

    Folder Structure

     - app
    - Containers
    - {container-name}
    - Resources
    - Languages
    - en
    - messages.php
    - users.php
    - ar
    - messages.php
    - users.php

    Usage

    Nothing much to show here, here's how you use translated strings:

    <?php

    __('messages.welcome');

    echo __('messages.welcome');

    dd(__('messages.welcome'));

    For more info about the localization checkout the Localization page.

    - + \ No newline at end of file diff --git a/docs/9.x/optional-components/mails/index.html b/docs/9.x/optional-components/mails/index.html index cd3d2115a..b180136ca 100644 --- a/docs/9.x/optional-components/mails/index.html +++ b/docs/9.x/optional-components/mails/index.html @@ -4,13 +4,13 @@ Mails | Apiato - +
    Version: 9.x

    Mails

    Definition

    The Mail component allows you to describe an email and send it whenever needed.

    For more details refer to this link.

    Principles

    • Containers MAY or MAY NOT have one or more Mail.

    • Ship may contain general Mails.

    Rules

    • All Notifications MUST extend from App\Ship\Parents\Mails\Mail.
    • Email Templates must be placed inside the Mail directory in a Templates directory app/Containers/{container}/Mails/Templates.

    Folder Structure

     - app
    - Containers
    - {container-name}
    - Mails
    - UserRegisteredMail.php
    - ...
    - Templates
    - user-registered.blade.php
    - ...
    - Ship
    - Mails
    - SomeMail.php
    - ...
    - Templates
    - some-template.blade.php
    - ...

    Code Samples

    Example: a simple Mail

    <?php

    namespace App\Containers\User\Mails;

    use App\Containers\User\Models\User;
    use Illuminate\Bus\Queueable;
    use App\Ship\Parents\Mails\Mail;
    use Illuminate\Contracts\Queue\ShouldQueue;

    class UserRegisteredMail extends Mail implements ShouldQueue
    {
    use Queueable;

    protected $user;

    public function __construct(User $user)
    {
    $this->user = $user;
    }

    public function build()
    {
    return $this->view('user::user-registered')
    ->to($this->user->email, $this->user->name)
    ->with([
    'name' => $this->user->name,
    ]);
    }
    }

    Usage from an Action:

    Notifications can be sent from Actions or Tasks using the Mail Facade.

    Mail::send(new UserRegisteredMail($user));

    Email Templates

    Templates should be placed inside a folder Templates inside the Mail folder.

    To access a Mail template (same like accessing a web view) you must call the container name then the view name.

    In the example below we're using the user-registered.blade.php template in the User Container.

    $this->view('user::user-registered')

    Configure Emails

    Open the .env file and set the From mail and address, this will be used globally whenever the from function is not called in the Mail.

    MAIL_FROM_ADDRESS=test@test.test
    MAIL_FROM_NAME="apiato"

    To use different email address in some classes add ->to($this->email, $this->name) to the build function in your Mail class.

    By default Apiato is configured to use Log Driver MAIL_DRIVER=log, you can change that from the .env file.

    Queueing A Notification

    To queue a notification you should use Illuminate\Bus\Queueable and implement Illuminate\Contracts\Queue\ShouldQueue.

    - + \ No newline at end of file diff --git a/docs/9.x/optional-components/middlewares/index.html b/docs/9.x/optional-components/middlewares/index.html index 7fa545455..05224768d 100644 --- a/docs/9.x/optional-components/middlewares/index.html +++ b/docs/9.x/optional-components/middlewares/index.html @@ -4,7 +4,7 @@ Middlewares | Apiato - + @@ -12,7 +12,7 @@
    Version: 9.x

    Middlewares

    Definition

    Middleware provide a convenient mechanism for filtering HTTP requests entering your application. More about them here.

    You can enable and disable Middlewares as you wish.

    Principles

    • There are two types of Middlewares, General (applied on all the Routes by default) and Endpoints Middlewares (applied on some Endpoints).

    • The Middlewares CAN be placed in Ship layer or Container layer depending on its roles.

    Rules

    • If a Middleware is written inside a Container it MUST be registered inside that Container.

    • To register Middlewares in a Container the container needs to have a MiddlewareServiceProvider, and like all other Container Providers it MUST be registered in the MainServiceProvider of that Container.

    • General Middlewares (like some default Laravel Middlewares) SHOULD live in the Ship layer app/Ship/Middlewares/* and are registered in the Ship Main Provider.

    • Third Party packages Middleware CAN be registered in Containers or on the Ship layer (wherever they make more sense). Example: the jwt.auth middleware "provided by the JWT package" is registered in the Authentication Container (Containers/Authentication/Providers/MiddlewareServiceProvider.php).

    Folder Structure

     - App
    - Containers
    - {container-name}
    - Middlewares
    - WebAuthentication.php
    - Ship
    - Middleware
    - Http
    - EncryptCookies.php
    - VerifyCsrfToken.php

    Code Sample

    Middleware Example:

    <?php

    namespace App\Containers\Authentication\Middlewares;

    use App\Ship\Engine\Butlers\Facades\ContainersButler;
    use App\Ship\Parents\Middlewares\Middleware;
    use Closure;
    use Illuminate\Contracts\Auth\Guard;
    use Illuminate\Http\Request;

    /**
    * Class WebAuthentication
    *
    * @author Mahmoud Zalt <mahmoud@zalt.me>
    */
    class WebAuthentication extends Middleware
    {

    protected $auth;

    public function __construct(Guard $auth)
    {
    $this->auth = $auth;
    }

    public function handle(Request $request, Closure $next)
    {
    if ($this->auth->guest()) {
    return response()->view(ContainersButler::getLoginWebPageName(), [
    'errorMessage' => 'Credentials Incorrect.'
    ]);
    }

    return $next($request);
    }
    }

    Middleware registration inside the Container Example:

    <?php

    namespace App\Containers\Authentication\Providers;

    use App\Containers\Authentication\Middlewares\WebAuthentication;
    use App\Ship\Parents\Providers\MiddlewareProvider;
    use Tymon\JWTAuth\Middleware\GetUserFromToken;
    use Tymon\JWTAuth\Middleware\RefreshToken;

    class MiddlewareServiceProvider extends MiddlewareProvider
    {

    protected $middleware = [

    ];

    protected $middlewareGroups = [
    'web' => [

    ],
    'api' => [

    ],
    ];

    protected $routeMiddleware = [
    'jwt.auth' => GetUserFromToken::class,
    'jwt.refresh' => RefreshToken::class,
    'auth:web' => WebAuthentication::class,
    ];

    public function boot()
    {
    $this->loadContainersInternalMiddlewares();
    }

    public function register()
    {

    }
    }

    Middleware registration inside the Ship layer (HTTP Kernel) Example:

    <?php

    namespace App\Ship\Kernels;

    use App\Ship\Middlewares\Http\ProcessETagHeadersMiddleware;
    use App\Ship\Middlewares\Http\ProfilerMiddleware;
    use App\Ship\Middlewares\Http\ValidateJsonContent;
    use Illuminate\Foundation\Http\Kernel as LaravelHttpKernel;

    /**
    * Class HttpKernel
    *
    * A.K.A (app/Http/Kernel.php)
    *
    * @author Mahmoud Zalt <mahmoud@zalt.me>
    */
    class HttpKernel extends LaravelHttpKernel
    {

    /**
    * The application's global HTTP middleware stack.
    *
    * These middleware are run during every request to your application.
    *
    * @var array
    */
    protected $middleware = [
    // Laravel middleware's
    \Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode::class,
    \Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
    \Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
    \App\Ship\Middlewares\Http\TrimStrings::class,
    \App\Ship\Middlewares\Http\TrustProxies::class,

    // CORS package middleware
    \Barryvdh\Cors\HandleCors::class,
    ];

    /**
    * The application's route middleware groups.
    *
    * @var array
    */
    protected $middlewareGroups = [
    'web' => [
    \App\Ship\Middlewares\Http\EncryptCookies::class,
    \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
    \Illuminate\Session\Middleware\StartSession::class,
    \Illuminate\View\Middleware\ShareErrorsFromSession::class,
    \App\Ship\Middlewares\Http\VerifyCsrfToken::class,
    \Illuminate\Routing\Middleware\SubstituteBindings::class,
    ],

    'api' => [
    ValidateJsonContent::class,
    'bindings',
    ProcessETagHeadersMiddleware::class,
    ProfilerMiddleware::class,
    // The throttle Middleware is registered by the RoutesLoaderTrait in the Core
    ],
    ];

    /**
    * The application's route middleware.
    *
    * These middleware may be assigned to groups or used individually.
    *
    * @var array
    */
    protected $routeMiddleware = [
    'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class,
    'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
    'can' => \Illuminate\Auth\Middleware\Authorize::class,
    'auth' => \Illuminate\Auth\Middleware\Authenticate::class,
    ];

    }
    - + \ No newline at end of file diff --git a/docs/9.x/optional-components/migrations/index.html b/docs/9.x/optional-components/migrations/index.html index cb37c905c..ca943938b 100644 --- a/docs/9.x/optional-components/migrations/index.html +++ b/docs/9.x/optional-components/migrations/index.html @@ -4,13 +4,13 @@ Migrations | Apiato - +
    Version: 9.x

    Migrations

    Definition

    Migrations (are the short name for Database Migrations).

    Migrations are the version control of your database. They are very useful for generating and documenting the database tables.

    Principles

    • Migrations SHOULD be created inside the Containers folders.

    • Migrations will be autoloaded in the framework

    Rules

    • No need to publish the DB Migrations. Just run the artisan migrate command and Laravel will read the Migrations from the Containers.

    Folder Structure

     - app
    - Containers
    - User
    - Data
    - Migrations
    - 2200_01_01_000001_create_users_table.php
    - ...

    Code Samples

    User CreateUsersTable Migrations:


    <?php

    use Illuminate\Database\Migrations\Migration;
    use Illuminate\Database\Schema\Blueprint;

    class CreateUsersTable extends Migration
    {
    public function up()
    {
    Schema::create('users', function (Blueprint $table) {
    $table->increments('id');
    $table->string('name');
    $table->string('email')->unique();
    $table->string('password');
    $table->rememberToken();
    $table->timestamps();
    $table->softDeletes();
    });
    }

    public function down()
    {
    Schema::drop('users');
    }
    }

    For more information about the Database Migrations read this.

    - + \ No newline at end of file diff --git a/docs/9.x/optional-components/notifications/index.html b/docs/9.x/optional-components/notifications/index.html index 19fff213b..7492cffb4 100644 --- a/docs/9.x/optional-components/notifications/index.html +++ b/docs/9.x/optional-components/notifications/index.html @@ -4,7 +4,7 @@ Notifications | Apiato - + @@ -12,7 +12,7 @@
    Version: 9.x

    Notifications

    Definition

    Notifications allow you to inform the user about a state changes in your application.

    The Laravel notifications supports sending notifications across a variety channels (mail, SMS, Slack, Database...).

    When using the Database channel the notifications will be stored in a database to be displayed in your client interface.

    For more details refer to this link.

    Principles

    • Containers MAY or MAY NOT have one or more Notification.

    • Ship may contain Application general Notifications.

    Rules

    • All Notifications MUST extend from App\Ship\Parents\Notifications\Notification.

    Folder Structure

     - app
    - Containers
    - {container-name}
    - Notifications
    - UserRegisteredNotification.php
    - ...
    - Ship
    - Notifications
    - SystemFailureNotification.php
    - ...

    Code Samples

    Example: a simple Notification

    <?php

    namespace App\Containers\User\Notifications;

    use App\Containers\User\Models\User;
    use App\Ship\Parents\Notifications\Notification;
    use Illuminate\Bus\Queueable;
    use Illuminate\Contracts\Queue\ShouldQueue;

    class BirthdayReminderNotification extends Notification implements ShouldQueue
    {

    use Queueable;

    protected $notificationMessage;

    public function __construct($notificationMessage)
    {
    $this->notificationMessage = $notificationMessage;
    }

    public function toArray($notifiable)
    {
    return [
    'content' => $this->notificationMessage,
    ];
    }

    public function toMail($notifiable)
    {
    // $notifiable is the object you want to notify "e.g. user"
    return (new MailMessage)
    ->subject("Hello World")
    ->line("Hi, $notifiable->name")
    ->line($this->notificationMessage);
    }

    public function toSms($notifiable)
    {
    // ...
    }

    // ...
    }

    Usage from an Action or Task:

    Notifications can be sent from Actions or Tasks using the Notification Facade.

    \Notification::send($user, new BirthdayReminderNotification($notificationMessage));

    Alternatively you can use the Illuminate\Notifications\Notifiable trait on the notifiable object "e.g. User" and then call it as follows:

    // get any user
    $user = User::firstOrCreate([
    'name' => 'Mahmoud Zalt',
    'email' => 'mail@something.com',
    'phone' => '0096123456789',
    ]);

    // call notify, found on the Notifiable trait
    $user->notify(new BirthdayReminderNotification($notificationMessage));

    Select Channels

    To select a notification channel, apiato have the app/Ship/Configs/notification.php config file where you can define the array of supported channels "e.g. SMS, Email, WebPush...", to be used for all your notifications.

    If you want to override the configuration for some notifications classes, or if you prefer to define the channels within each notification class itself, you can override the via function public function via($notifiable) in the notification class and define your channels.

    Checkout laravel notification channels for list of supported integrations.

    Queueing a Notification

    To queue a notification you should use Illuminate\Bus\Queueable and implement Illuminate\Contracts\Queue\ShouldQueue.

    Use DB channel

    Generally you need to generate the notification migration php artisan notifications:table, then run php artisan migrate, however just running the migration command will do the job, since Apiato already adds the _create_notifications_table.php in the default migrations files directory app/Ship/Migrations/.

    - + \ No newline at end of file diff --git a/docs/9.x/optional-components/providers/index.html b/docs/9.x/optional-components/providers/index.html index 0c2188605..f6111aeaa 100644 --- a/docs/9.x/optional-components/providers/index.html +++ b/docs/9.x/optional-components/providers/index.html @@ -4,7 +4,7 @@ Providers | Apiato - + @@ -17,7 +17,7 @@ In apiato those providers have been renamed and moved to the Ship Layer app/Ship/Parents/Providers/*:

    • AppServiceProvider
    • RouteServiceProvider
    • AuthServiceProvider
    • BroadcastServiceProvider
    • EventsServiceProvider

    VIP Note: you should not touch those providers, instead you have to extend them from a containers providers in order to modify them. Example: the app/Containers/Authentication/Providers/AuthProvider.php is extending the AuthServiceProvider to modify it.

    Those providers are not auto registered by default, thus writing any code there will not be available, unless you extend them. Once extended the child Provider should be registered in its Container Main Provider, which makes its parent available.

    This rule does not apply to the RouteServiceProvider since it's required by Apiato, this Provider is registered by the ApiatoProvider.

    Check How Service Providers are auto-loaded.

    - + \ No newline at end of file diff --git a/docs/9.x/optional-components/repositories/index.html b/docs/9.x/optional-components/repositories/index.html index ca42ab94e..d49955096 100644 --- a/docs/9.x/optional-components/repositories/index.html +++ b/docs/9.x/optional-components/repositories/index.html @@ -4,13 +4,13 @@ Repositories | Apiato - +
    Version: 9.x

    Repositories

    Definition

    The Repository classes are an implementation of the Repository Design Pattern.

    Their major roles are separating the business logic from the data (or the data access Task).

    Repositories save and retrieves Models to/from the underlying storage mechanism.

    The Repository is used to separate the logic that retrieves the data and maps it to a Model, from the business logic that acts on the Model.

    Principles

    • Every Model SHOULD have a Repository.

    • A Model SHOULD always get accessed through its Repository. (Never direct access to Model).

    Rules

    • All Repositories MUST extend from App\Ship\Parents\Repositories\Repository. Extending from this class will give access to functions like (find, create, update and much more).

    • Repository name should be same like it's model name (model: Foo -> repository: FooRepository).

    • If a Repository belongs to a Model whose name is not equal to its Container name, then the Repository must set the $container property like this: $container='ContainerName'. See an example below

    Folder Structure

     - app
    - Containers
    - {container-name}
    - Data
    - Repositories
    - UserRepository.php
    - ...

    Code Samples

    User Repository:

    <?php

    namespace App\Containers\User\Data\Repositories;

    use App\Containers\User\Contracts\UserRepositoryInterface;
    use App\Containers\User\Models\User;
    use App\Ship\Parents\Repositories\Repository;

    class UserRepository extends Repository implements UserRepositoryInterface
    {
    protected $fieldSearchable = [
    'name' => 'like',
    'email' => '=',
    ];
    }

    Usage:

    <?php

    // paginate the data by 10
    $users = $userRepository->paginate(10);

    // search by 1 field
    $cars = $carRepository->findByField('colour', $colour);

    // searching multiple fields
    $offer = $offerRepository->findWhere([
    'offer_id' => $offer_id,
    'user_id' => $user_id,
    ])->first();

    //....

    Note: If the Repository belongs to Model with a name different from its Container name, the Repository class of that Model must set the property $container and define the Container name.

    Example:

    <?php

    namespace App\Containers\Authorization\Data\Repositories;

    use App\Ship\Parents\Repositories\Repository;

    class RoleRepository extends Repository
    {
    protected $container = 'Authorization'; // the container name. Must be set when the model has different name than the container

    protected $fieldSearchable = [

    ];

    }

    Other Properties:

    API Query Parameters Property

    To enable query parameters (?search=text,...) in your API you need to set the property $fieldSearchable on the Repository class, to instruct the querying on your model.

    Example $fieldSearchable of a Repository:

         <?php

    protected $fieldSearchable = [
    'name' => 'like',
    'email' => '=',
    ];

    Continue reading to find more about those properties and what they do.

    All other Properties

    apiato uses the andersao/l5-repository package, to provide a lot of powerful features to the repository class. such as

    <?php

    // ...

    protected $cacheMinutes = 1440; // 1 day

    protected $cacheOnly = ['all'];

    To learn more about all the properties you can use, visit the andersao/l5-repository package documentation.

    - + \ No newline at end of file diff --git a/docs/9.x/optional-components/seeders/index.html b/docs/9.x/optional-components/seeders/index.html index 556f2cb14..aaa1d718a 100644 --- a/docs/9.x/optional-components/seeders/index.html +++ b/docs/9.x/optional-components/seeders/index.html @@ -4,13 +4,13 @@ Seeders | Apiato - +
    Version: 9.x

    Seeders

    Definition

    Seeders (are a short name for Database Seeders).

    Seeders are classes made to seed the database with real data, this data usually should exist in the Application after the installation (Example: the default Users Roles and Permissions or the list of Countries).

    Principles

    • Seeders SHOULD be created in the Containers. (If the container is using a package that publishes a Seeder class, this class should be manually placed in the Container that make use of it. Do not reply on the package to place it on its right location).

    Rules

    • Seeders should be in the right directory inside the container to be loaded.

    • To avoid any conflict between containers seeders classes, you SHOULD always prepend the Seeders of each container with the container name. (Example: UserPermissionsSeeder, ItemPermissionsSeeder). If 2 seeders classes have the same name but live in different containers, one of them will not be loaded.

    • If you wish to order the seeding of the classes, you can just append _1, _2 to your classes.

    Folder Structure

     - App
    - Containers
    - {container-name}
    - Data
    - Seeders
    - ContainerNameRolesSeeder_1.php
    - ContainerNamePermissionsSeeder_2.php
    - ...

    Code Samples

    Roles Seeder:

    <?php

    namespace App\Containers\Order\Data\Seeders;

    use App\Ship\Parents\Seeders\Seeder;
    use Apiato\Core\Foundation\Facades\Apiato;

    class OrderPermissionsSeeder_1 extends Seeder
    {

    public function run()
    {
    Apiato::call('Authorization@CreatePermissionTask', ['approve-reject-orders']);
    Apiato::call('Authorization@CreatePermissionTask', ['find-orders']);
    Apiato::call('Authorization@CreatePermissionTask', ['list-orders']);
    Apiato::call('Authorization@CreatePermissionTask', ['update-orders']);
    Apiato::call('Authorization@CreatePermissionTask', ['delete-orders']);

    // ...

    }
    }

    Note: Same Seeder class is allowed to contain seeding for multiple Models.

    Run the Seeders

    After registering the Seeders you can run this command:

    php artisan db:seed

    To run specific Seeder class you can specify its class in the parameter as follows:

    php artisan db:seed --class="your\single\seeder\goes-here"

    Migrate & seed at the same time

    php artisan migrate --seed

    For more information about the Database Seeders read this.

    Apiato testing seeder command

    It's useful sometimes to create a big set of testing data. apiato facilitates this task:

    1. Open app/Ship/Seeders/SeedTestingData.php and write your testing data here.
    2. Run this command any time you want this data available (example at staging servers):
    php artisan apiato:seed-test
    - + \ No newline at end of file diff --git a/docs/9.x/optional-components/tests/index.html b/docs/9.x/optional-components/tests/index.html index 5e9d9e73a..bde67c7fa 100644 --- a/docs/9.x/optional-components/tests/index.html +++ b/docs/9.x/optional-components/tests/index.html @@ -4,13 +4,13 @@ Tests | Apiato - +
    Version: 9.x

    Tests

    Definition

    Tests classes are created to test the Application classes are working as expected.

    The two most essential Tests types for this architecture are the Unit Tests and the Functional Tests. However, Integration and Acceptance Tests can be used as well.

    Principles

    • Containers MAY be covered by all types of Tests.

    • Use Functional Tests to test Container Routes are doing what's expected from them.

    • Use Unit Tests to test Container Actions and Tasks are doing what's expected from them.

    Rules

    • All Container Tests classes SHOULD extend from a Container Internal TestCase class {container-name}/tests/TestCase.php. The container TestCase MUST extend main TestCase on Ship layer App\Ship\Parents\Tests\PhpUnit\TestCase. (Adding functions to the container TestCase allows sharing those functions between all Test classes of the Container).

    Folder Structure

     - app
    - Containers
    - {container-name}
    - Tests
    - TestCase.php // the container test case
    - Unit
    - CreateUserTest.php
    - UpdateUserTest.php
    - ...
    - UI
    - API
    - Tests
    - Functional
    - LoginTest.php
    - LogoutTest.php
    - ...
    - WEB
    - Tests
    - Functional
    - LoginTest.php
    - LogoutTest.php
    - ...
    - CLI
    - Tests
    - Functional
    - BackupDataTest.php
    - ...

    Code Sample

    <?php

    namespace App\Containers\User\UI\API\Tests\Functional;

    use App\Containers\{container-name}\Tests\TestCase;

    class DeleteUserTest extends TestCase
    {
    protected $endpoint = '/users';

    protected $permissions = [
    'delete-users'
    ];

    public function testDeleteExistingUser_()
    {
    // get a testing user of type admin.
    $user = $this->getLoggedInTestingAdmin();

    // send the HTTP request
    $response = $this->apiCall($this->endpoint, 'delete');

    // assert response status is correct
    $this->assertEquals($response->getStatusCode(), '202');

    // ...
    }

    }

    See the Tests Helpers Page

    - + \ No newline at end of file diff --git a/docs/9.x/optional-components/values/index.html b/docs/9.x/optional-components/values/index.html index 5946598d0..74075a023 100644 --- a/docs/9.x/optional-components/values/index.html +++ b/docs/9.x/optional-components/values/index.html @@ -4,7 +4,7 @@ Values | Apiato - + @@ -12,7 +12,7 @@
    Version: 9.x

    Values

    Definition & Principles

    Values are short names for the known "Value Objects" which are simple Objects, pretty similar to Models in the concept of representing data, but they do not get stored in the DB, thus they don't have ID's. They also do not hold functionality or change any state, they just hold data.

    A Value Object is an immutable object that is defined by its encapsulated attributes. We create Value Object when we need it to represent/serve/manipulate some data (attached as attributes), and we'll kill it later when we finish using it, to recreate it again when needed.

    Rules

    • All Models MUST extend from App\Ship\Parents\Values\Value.

    Folder Structure

     - App
    - Containers
    - {container-name}
    - Values
    - Output.php
    - Region.php
    - ...

    Code Sample

    <?php

    use App\Ship\Parents\Values\Value;

    class Location extends Value
    {
    private $x = null;

    private $y = null;

    protected $resourceKey = 'locales';

    public function __construct($x, $y)
    {
    $this->x = $x;
    $this->y = $y;
    }

    public function getCoordinatesAsString()
    {
    return $this->x . ' - ' . $this->y;
    }
    }
    - + \ No newline at end of file diff --git a/docs/9.x/upgrade-guide/index.html b/docs/9.x/upgrade-guide/index.html index 25d82975f..71aa71594 100644 --- a/docs/9.x/upgrade-guide/index.html +++ b/docs/9.x/upgrade-guide/index.html @@ -4,7 +4,7 @@ Upgrade Guide | Apiato - + @@ -22,7 +22,7 @@ and the term New Project (referring to the new freshly installed Apiato 5.0).

    1) Download and install Apiato 5.0. See Application Setup.

    2) Delete the Containers directory app/Containers from the new project.

    3) Move the Containers directory app/Containers from the old project to the new project.

    4) Open this file app/Ship/composer.json in your old project and only copy the required dependencies, from the old project to the same file in the new project.

    5) Again, open the app/Ship/composer.json file in the new project, and remove the following dependencies: guzzlehttp/guzzle, prettus/l5-repository, barryvdh/laravel-cors, spatie/laravel-fractal, vinkla/hashids and johannesschobel/apiato-container-installer.

    6) Move and replace the following directories from the old project to the new project: config, public, resources, database and storage.

    7) Open config/app.php and replace App\Ship\Engine\Providers\PortoServiceProvider::class with Apiato\Core\Providers\ApiatoProvider::class.

    8) Move .gitignore, phpunit.xml and .env files, from the old project to the new project.

    9) Open the .env file on the new project and append this to it API_RATE_LIMIT_ENABLED=true.

    10) Open phpunit.xml file of the new project and delete this line from the file <file>./app/Ship/Engine/Loaders/FactoryMixer/FactoriesLoader.php</file>.

    11) If you had live testing data in your old project inside app/Ship/Seeders/Data/Testing/Seeders/TestingDataSeeder.php file, then copy that file content and past it in the new project inside app/Ship/Seeders/SeedTestingData.php. You will need to rename the class (not the file) from TestingDataSeeder to SeedTestingData, and you will need to update the namespace from namespace App\Ship\Seeders\Data\Testing\Seeders; to namespace App\Ship\Seeders;.

    12) If you ever used the HashIdTrait, you need to search and replace this namespace App\Ship\Engine\Traits\HashIdTrait with this Apiato\Core\Traits\HashIdTrait.

    13) Run composer update. If you got any error at this step, try to solve it or open an Issue.

    14) Move the .git directory from the old project to the new one. Add all changes git add . then commit git commit -m 'upgrade Apiato from 4.1 to 5.0'.

    15) Run your tests vendor/bin/phpunit.

    That's it :)

    How to manually upgrade older versions to 4.1?

    Use the Manual Upgrading Guide below.

    Manual Upgrading Guide

    These commands and examples, are compatible with the Apiato 8.0 upgrade. You can just copy/past.

    1) Checkout a new branch from your stable branch, to perform the upgrade.

    git checkout -b upgrade-apiato

    2) Configure a new remote (upstream) that points to the official Apiato repository.

    git remote add upstream https://github.com/apiato/apiato

    Verify the new upstream repository was added, by listing the current configured remote repositories.

    git remote -vv

    origin git@bitbucket.org:username/my-awesome-api.git (fetch)
    origin git@bitbucket.org:username/my-awesome-api.git (push)
    upstream git@github.com:apiato/apiato.git (fetch)
    upstream git@github.com:apiato/apiato.git (push)

    3) Checkout a new branch to hold the latest Apiato changes. This branch will be merged into your upgrade-apiato branch created above.

    git checkout -b apiato-{version}
    // Example: git checkout -b apiato-8.0

    4) Configure this branch to track an upstream specific branch.

    Replace {upstream-branch-name} with the branch name you want to upgrade to (for example 8.0).

    git fetch upstream {upstream-branch-name}
    // Example: git fetch upstream 8.0

    git branch --set-upstream-to upstream/{upstream-branch-name}
    // Example: git branch --set-upstream-to upstream/8.0

    Verify your local branch is tracking the Apiato specified upstream branch.

    git branch -vv

    apiato 77b4d945 [upstream/{upstream-branch-name}] ...
    master 77d302aa [origin/master] ...

    5) Make this branch identical to the remote upstream branch

    git reset --hard upstream/{upstream-branch-name}
    // Example: git reset --hard upstream/8.0

    Verify this branch now contains the latest changes from the upstream branch.

    git log

    6) Switch back to the upgrade-apiato branch

    git checkout upgrade-apiato

    7) Now lets merge the 2 branches. This step can be done in two ways:

    Option A: Merge all the changes together and solve the conflicts if any. (Recommended)

    You can execute the next command with different different parameters, below are 2 options to pick whatever feels safer to you. Do not execute both of them.

    A1: This will overwrite your changes with the upstream changes. (Try this first and if your tests failed then you can try the second one).

    git merge --allow-unrelated-histories --strategy-option=theirs apiato-{version}
    // Example: git merge --allow-unrelated-histories --strategy-option=theirs apiato-8.0

    A2: This will let you solve all the conflicts manually. (Can be the most secure choice, but it's time consuming as well.)

    git merge --allow-unrelated-histories apiato-{version}
    // Example: git merge --allow-unrelated-histories apiato-8.0

    Option B: Manually cherry pick the commits you likes to have:

    git log {upstream-branch-name}

    (copy each commit ID, one by one)

    git cherry-pick {commit-ID}

    (if you get any conflict solve it and keep moving)

    8) Compare your .env with the new .env-example and update it.

    9) Check everything is working. By running Composer install first then re-running your tests.

    • Read the changelog releases page.
    • You may want to update your custom containers dependencies, simply follow the composer install error outputs and bump each failing dependency. (Hint: visit each package releases page, and use the version which supports the supported version of Laravel).
    • You may need to fix the failing tests.
    composer install  &&  vendor/bin/phpunit

    10) Finally, merge the upgrade-apiato (which contains the upgraded changes) with your stable branch (could be master).

    git checkout master
    git merge upgrade-apiato

    php artisan -V

    Enjoy :)

    - + \ No newline at end of file diff --git a/docs/architecture-concepts/components/index.html b/docs/architecture-concepts/components/index.html index 4d15181b0..aa5bf7976 100644 --- a/docs/architecture-concepts/components/index.html +++ b/docs/architecture-concepts/components/index.html @@ -4,7 +4,7 @@ Components | Apiato - + @@ -19,7 +19,7 @@ simplifying future maintenance and facilitating modifications when needed.

    Components in Porto are categorized into two types: Main Components and Optional Components.

    Main Components

    Main Components are essential for the Container's functionality and must be used to achieve its core purpose.

    Optional Components

    Optional Components offer additional functionality that can be incorporated into the Container. Their usage is discretionary, depending on specific requirements.

    tip

    To learn more about how all this fits together, read the Request Lifecycle page.

    - + \ No newline at end of file diff --git a/docs/architecture-concepts/container/index.html b/docs/architecture-concepts/container/index.html index bb840695f..41666bff3 100644 --- a/docs/architecture-concepts/container/index.html +++ b/docs/architecture-concepts/container/index.html @@ -4,7 +4,7 @@ Container | Apiato - + @@ -23,7 +23,7 @@ you may use the apiato:generate:container interactive command:

    php artisan apiato:generate:container

    Composer Dependencies

    To manage Composer dependencies, follow these guidelines:

    • All the Composer dependencies for a specific Container should be defined within that Container's composer.json file.
    • Dependencies related to the Ship layer should be placed in the root of the Ship layer, in a composer.json file.
    • Framework core dependencies should be defined in the project's root-level composer.json file.

    In practice, you can choose to place Composer dependencies in any of these composer.json files, and they will perform the same function. The choice of location depends on what is most relevant and convenient for your project.

    Readme

    Each Container has the option to include a readme.md file at its root, which serves to explain the Container's purpose and how to use it.

    To generate new readme files, you may use the apiato:generate:readme interactive command:

    php artisan apiato:generate:readme
    - + \ No newline at end of file diff --git a/docs/architecture-concepts/index.html b/docs/architecture-concepts/index.html index 9538408c2..caa12df81 100644 --- a/docs/architecture-concepts/index.html +++ b/docs/architecture-concepts/index.html @@ -4,7 +4,7 @@ Architecture Concepts | Apiato - + @@ -13,7 +13,7 @@ to structure the application code.

    Investing 30 minutes in reading the Porto Documentation before getting started is highly recommended and can prove to be a valuable use of your time. The document serves as a comprehensive guide and resource for understanding the Apiato project.

    - + \ No newline at end of file diff --git a/docs/architecture-concepts/porto/index.html b/docs/architecture-concepts/porto/index.html index a40c0fdaf..b20c43eb7 100644 --- a/docs/architecture-concepts/porto/index.html +++ b/docs/architecture-concepts/porto/index.html @@ -4,7 +4,7 @@ Porto | Apiato - + @@ -18,7 +18,7 @@ It can be a specific feature or a wrapper around a RESTful API resource.

    note

    A Container is allowed to depend on other Containers in the same Section.

    Ship

    The Ship layer contains the infrastructure code, which consists of shared code utilized by all Containers.

    Typical Project Structure

    app
    ├── Containers
    │ ├── Section
    │ │ └── Container
    │ │ ├── Actions
    │ │ ├── Configs
    │ │ ├── Data
    │ │ │ ├── Factories
    │ │ │ ├── Migrations
    │ │ │ ├── Repositories
    │ │ │ └── Seeders
    │ │ ├── Mails
    │ │ │ └── Templates
    │ │ ├── Middlewares
    │ │ ├── Models
    │ │ ├── Notifications
    │ │ ├── Providers
    │ │ ├── Tasks
    │ │ ├── Tests
    │ │ ├── Traits
    │ │ └── UI
    │ │ ├── API
    │ │ │ ├── Controllers
    │ │ │ ├── Requests
    │ │ │ ├── Routes
    │ │ │ └── Transformers
    │ │ ├── WEB
    │ │ │ ├── Controllers
    │ │ │ ├── Requests
    │ │ │ ├── Routes
    │ │ │ └── Views
    │ │ └── CLI
    │ │ └── Commands
    │ └── Vendor `// All installed and reusable Containers`
    │ ├── ContainerA
    │ └── ContainerB
    └── Ship `// All shared code between all Containers`
    ├── Broadcasts
    ├── Commands
    ├── Configs
    ├── Contracts
    ├── Criterias
    ├── Events
    ├── Exceptions
    ├── Generators
    ├── Helpers
    ├── Kernels
    ├── Listeners
    ├── Mails
    ├── Middlewares
    ├── Migrations
    ├── Notifications
    ├── Parents
    ├── Providers
    ├── Seeders
    └── Tests

    Default Sections

    Apiato ships with two default Sections:

    • AppSection: contains all the default Containers.
    • Vendor: contains all the installed and reusable Containers.
    tip

    The Vendor section is a special Section within the Containers layer that holds installed and reusable Containers. It serves a similar purpose as the vendor folder located at the root. Any Section is permitted to depend on the Vendor Section, allowing for the utilization of its Containers.

    Read more about the Container Installer to learn how to install Vendor Containers.

    - + \ No newline at end of file diff --git a/docs/architecture-concepts/request-lifecycle/index.html b/docs/architecture-concepts/request-lifecycle/index.html index b4a6aa9ef..66d62cb45 100644 --- a/docs/architecture-concepts/request-lifecycle/index.html +++ b/docs/architecture-concepts/request-lifecycle/index.html @@ -4,7 +4,7 @@ Request Lifecycle | Apiato - + @@ -16,7 +16,7 @@ The Tasks can be used to execute reusable subsets of the business logic, with each Task responsible for a single portion of the main Action. The View or Transformer is used to build the response that is sent back to the User.

    Request Lifecycle Diagram

    Legend:

    • Solid Line: Mandatory dependency (always used)
    • Doted Line: Optional dependency (not always used)
    • Red Solid Border: Response generation
    • Green Dashed Border: Optional component (not always used)
    - + \ No newline at end of file diff --git a/docs/components/index.html b/docs/components/index.html index a6c34b555..527ec6bbe 100644 --- a/docs/components/index.html +++ b/docs/components/index.html @@ -4,7 +4,7 @@ Components | Apiato - + @@ -13,7 +13,7 @@ "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119.

    info

    To learn more about Apiato components, check the Components section.

    - + \ No newline at end of file diff --git a/docs/components/main-components/actions/index.html b/docs/components/main-components/actions/index.html index 906767323..a53339ea4 100644 --- a/docs/components/main-components/actions/index.html +++ b/docs/components/main-components/actions/index.html @@ -4,7 +4,7 @@ Actions | Apiato - + @@ -20,7 +20,7 @@ However, it's important to note that not all operations may be automatically rolled back. For example, file system operations, such as uploading an image, are typically not covered by the database transaction and would need to be handled manually.

    - + \ No newline at end of file diff --git a/docs/components/main-components/controllers/index.html b/docs/components/main-components/controllers/index.html index 37fb12648..fed935917 100644 --- a/docs/components/main-components/controllers/index.html +++ b/docs/components/main-components/controllers/index.html @@ -4,7 +4,7 @@ Controllers | Apiato - + @@ -16,7 +16,7 @@ and it MUST be used in conjunction with the transform method. This is different from the meta parameter in the transform method. This metadata will be returned directly under the meta key.

    You can use this method in conjunction with the meta parameter in the transform method.

    $metaData = ['foo' => 999, 'bar'];

    $this->withMeta($metaData)->transform($sample, SampleTransformer::class, meta: ['foo' => 'bar', 'baz' => 1]);

    // Response
    {
    "data": {},
    "meta": {
    "foo": 999,
    "0": "bar",
    "include": [...],
    "custom": {
    "foo": "bar",
    "baz": 1
    },
    "pagination": {}
    }
    }

    json

    This method allows you to pass an array of data that will be represented as JSON.

    $this->json($data)

    created

    This method allows you to return a response with a 201 status code.

    $this->created($data)

    deleted

    This method allows you to return a response with a 202 status code.

    $this->deleted($deletedModel)

    // Response
    {
    "message": "Model (1) Deleted Successfully."
    }

    accepted

    This method allows you to return a response with a 202 status code.

    $this->accepted($data)

    noContent

    This method allows you to return a response with a 204 status code.

    $this->noContent()
    - + \ No newline at end of file diff --git a/docs/components/main-components/exceptions/index.html b/docs/components/main-components/exceptions/index.html index 642d5b352..b9b058397 100644 --- a/docs/components/main-components/exceptions/index.html +++ b/docs/components/main-components/exceptions/index.html @@ -4,7 +4,7 @@ Exceptions | Apiato - + @@ -13,7 +13,7 @@ Translation strings are automatically translated if the translations are found. To handle localization, you can use the Localization Container.

    // Example 1
    throw (new AccountFailedException())->withErrors(['email' => 'appSection@user::exceptions.email-taken']);
    // Example 2
    throw (new AccountFailedException())->withErrors(['email' => 'appSection@user::exceptions.email-taken', 'Another not translated message']);

    Response:

    {
    "message": "The exception error message.",
    "errors": {
    "email": [
    "The email has already been taken.",
    "Another not translated message"
    ]
    }
    }

    debug

    The debug method is used for logging error messages during debugging and development. The debug method accepts string or \Exception instance

    throw (new AccountFailedException())->debug($e);
    - + \ No newline at end of file diff --git a/docs/components/main-components/index.html b/docs/components/main-components/index.html index 9ddeea43e..d3c8ea008 100644 --- a/docs/components/main-components/index.html +++ b/docs/components/main-components/index.html @@ -4,13 +4,13 @@ Main Components | Apiato - + - + \ No newline at end of file diff --git a/docs/components/main-components/models/index.html b/docs/components/main-components/models/index.html index 2501ee716..07ae1eb3c 100644 --- a/docs/components/main-components/models/index.html +++ b/docs/components/main-components/models/index.html @@ -4,7 +4,7 @@ Models | Apiato - + @@ -16,7 +16,7 @@ it is essential to incorporate the ModelTrait trait into your model. By doing so, your model will benefit from various functionalities provided by the trait, such as hash ids and other features necessary for proper integration with the framework.

    use Apiato\Core\Traits\ModelTrait;

    class Demo
    {
    use ModelTrait;
    ...
    }
    - + \ No newline at end of file diff --git a/docs/components/main-components/requests/index.html b/docs/components/main-components/requests/index.html index 33aefdcce..dab099320 100644 --- a/docs/components/main-components/requests/index.html +++ b/docs/components/main-components/requests/index.html @@ -4,7 +4,7 @@ Requests | Apiato - + @@ -73,7 +73,7 @@ which employs the Shallow technique. This middleware can be particularly valuable in reducing bandwidth usage for clients, especially on mobile devices.

    Please note that this feature is disabled by default. To enable it, follow these steps:

    1. Navigate to the app/Ship/Configs/apiato.php configuration file.
    2. Inside the configuration file, locate the use-etag configuration parameter.
    3. Set the use-etag parameter to true.

    Keep in mind that for this feature to function correctly, the client must include the If-None-Match HTTP header, which corresponds to the ETag value, in their request.

    - + \ No newline at end of file diff --git a/docs/components/main-components/routes/index.html b/docs/components/main-components/routes/index.html index 5867ab031..95f6ea2c9 100644 --- a/docs/components/main-components/routes/index.html +++ b/docs/components/main-components/routes/index.html @@ -4,7 +4,7 @@ Routes | Apiato - + @@ -18,7 +18,7 @@ Maintaining this distinction enables the generation of separate documentations for each type, ensuring that your internal API remains private and secure. This feature can be configured through the Documentation Generator package.

    Public Routes:

    • Accessible to third parties.
    • May or may not require authentication.

    Private Routes:

    • Accessible only to your own apps.
    • May or may not require authentication.
    - + \ No newline at end of file diff --git a/docs/components/main-components/subactions/index.html b/docs/components/main-components/subactions/index.html index 19c8e1434..fccbe22d1 100644 --- a/docs/components/main-components/subactions/index.html +++ b/docs/components/main-components/subactions/index.html @@ -4,7 +4,7 @@ Sub Actions | Apiato - + @@ -13,7 +13,7 @@ They enable Actions to share a sequence of Tasks, thus promoting reusability. Similar to how Tasks enable Actions to share specific functionalities, SubActions serve to share a predefined set of Tasks.

    All the features and capabilities available for regular Actions are also applicable to SubActions.

    To generate new SubActions you may use the apiato:generate:subaction interactive command:

    php artisan apiato:generate:subaction

    Definition & Principles

    Read Porto SAP Documentation (#Sub-Actions).

    Rules

    • All SubActions:
      • MUST be placed in the app/Containers/{Section}/{Container}/Actions directory.
      • MUST extend the App\Ship\Parents\Actions\SubAction class.
        • The parent extension SHOULD be aliased as ParentSubAction.

    Folder Structure

    app
    └── Containers
    └── Section
    └── Container
    └── Actions
    ├── ValidateAddressSubAction.php
    ├── BuildOrderSubAction.php
    └── ...

    Code Example

    use ...
    use App\Ship\Parents\Actions\SubAction as ParentSubAction;

    class DemoSubAction extends ParentSubAction
    {
    public function __construct(
    private readonly DemoTask $demoTask
    ) {
    }

    public function run(array $data)
    {
    return $this->demoTask->run($data);
    }
    }
    - + \ No newline at end of file diff --git a/docs/components/main-components/tasks/index.html b/docs/components/main-components/tasks/index.html index e2974491a..0d6be6857 100644 --- a/docs/components/main-components/tasks/index.html +++ b/docs/components/main-components/tasks/index.html @@ -4,7 +4,7 @@ Tasks | Apiato - + @@ -15,7 +15,7 @@ in encapsulating functionalities that are utilized by multiple Actions spanning various Containers within your application.

    To generate new tasks you may use the apiato:generate:task interactive command:

    php artisan apiato:generate:task

    Additionally, to retrieve a list of the existing tasks in your Apiato application, use the apiato:list:tasks command.

    php artisan apiato:list:tasks

    Definition & Principles

    Read Porto SAP Documentation (#Tasks).

    Rules

    • All Tasks:
      • MUST be placed in the app/Containers/{Section}/{Container}/Tasks directory.
      • MUST extend the App\Ship\Parents\Tasks\Task class.
        • The parent extension SHOULD be aliased as ParentTask.

    Folder Structure

    app
    └── Containers
    └── Section
    └── Container
    └── Tasks
    ├── CreateResourceTask.php
    ├── DeleteResourceTask.php
    └── ...

    Code Example

    use ...
    use App\Ship\Parents\Tasks\Task as ParentTask;

    class DemoTask extends ParentTask
    {
    public function run(int $a, int $b): int
    {
    return $a + $b;
    }
    }
    - + \ No newline at end of file diff --git a/docs/components/main-components/transformers/index.html b/docs/components/main-components/transformers/index.html index 95e799d6c..8609393ef 100644 --- a/docs/components/main-components/transformers/index.html +++ b/docs/components/main-components/transformers/index.html @@ -4,7 +4,7 @@ Transformers | Apiato - + @@ -54,7 +54,7 @@ This serializer is not to everyone’s tastes, because it adds a data namespace to the output. A very basic response of the DataArraySerializer will look like this:

    {
    "data": {
    "object": "User",
    "id": "XbPW7awNkzl83LD6",
    "name": "Mohammad Alavi"
    }
    }

    The DataArraySerializer is handy because it allows space for meta data (like pagination, or totals) in both Items and Collections.

    {
    "data": [ ... ],
    "meta": {
    "include": [
    "xxx",
    "yyy"
    ],
    "custom": [],
    "pagination": {
    "total": 999,
    "count": 999,
    "per_page": 999,
    "current_page": 999,
    "total_pages": 999,
    "links": {
    "next": "http://api.apiato.test/v1/accounts?page=999"
    }
    }
    }
    }
    Further Reading

    For more detailed information, please refer to Fractal and Laravel Fractal Wrapper documentations.

    - + \ No newline at end of file diff --git a/docs/components/main-components/views/index.html b/docs/components/main-components/views/index.html index 622fb32f2..b13da1081 100644 --- a/docs/components/main-components/views/index.html +++ b/docs/components/main-components/views/index.html @@ -4,7 +4,7 @@ Views | Apiato - + @@ -17,7 +17,7 @@ such as view('welcome-page'), will result in the view not being found.

    An exception to this namespace convention is for view files located in the app/Ship/Views and app/Ship/Mails/Templates directories. These views will be namespaced using the word ship instead of the Section and Container names.

    For example, you would access such a view like this: view(ship::welcome-page).

    - + \ No newline at end of file diff --git a/docs/components/optional-components/commands/index.html b/docs/components/optional-components/commands/index.html index fa83b08ad..e8aa34db4 100644 --- a/docs/components/optional-components/commands/index.html +++ b/docs/components/optional-components/commands/index.html @@ -4,7 +4,7 @@ Commands | Apiato - + @@ -12,7 +12,7 @@
    Version: 12.x

    Commands

    Apiato commands are just Laravel Commands, and they function in the exact same way as Laravel commands. However, they come with additional rules and conventions specific to Apiato.

    Rules

    • All container-specific Commands MUST be placed in the app/Containers/{Section}/{Container}/UI/CLI/Commands directory.
    • All general Commands MUST be placed in the app/Ship/Commands directory.
    • All Commands:
      • MUST extend the App\Ship\Parents\Commands\ConsoleCommand class.
        • The parent extension SHOULD be aliased as ConsoleCommand.
      • SHOULD call an Action to perform its job, and SHOULD NOT contain any business logic.

    Folder Structure

    app
    ├── Containers
    │ └── Section
    │ └── Container
    │ └── UI
    │ └── CLI
    │ └── Commands
    │ ├── FirstCommand.php
    │ ├── SecondCommand.php
    │ └── ...
    └── Ship
    └── Commands
    ├── FirstCommand.php
    ├── SecondCommand.php
    └── ...

    Code Example

    Commands are defined exactly as you would define them in Laravel.

    Closure Commands

    You can define your console closure commands in app/Ship/Commands/closures.php.

    - + \ No newline at end of file diff --git a/docs/components/optional-components/configs/index.html b/docs/components/optional-components/configs/index.html index a05d5cad4..a07ec5818 100644 --- a/docs/components/optional-components/configs/index.html +++ b/docs/components/optional-components/configs/index.html @@ -4,7 +4,7 @@ Configs | Apiato - + @@ -17,7 +17,7 @@ camelCase representation of the container's Section name, succeeded by -, and then the camelCase representation of the Container name.

    For instance, if you have a container named "MyContainer" within the "MySection" section, the configuration file would be named mySection-myContainer.php.

    - + \ No newline at end of file diff --git a/docs/components/optional-components/events/index.html b/docs/components/optional-components/events/index.html index 69f414b63..e3f3204e3 100644 --- a/docs/components/optional-components/events/index.html +++ b/docs/components/optional-components/events/index.html @@ -4,7 +4,7 @@ Events | Apiato - + @@ -17,7 +17,7 @@ you may use the apiato:generate:provider interactive command:

    php artisan apiato:generate:provider

    Remember to also register the EventServiceProvider in the container's MainServiceProvider:

    use ...
    use App\Ship\Parents\Providers\MainServiceProvider as ParentMainServiceProvider;

    class MainServiceProvider extends ParentMainServiceProvider
    {
    protected array $serviceProviders = [
    // ... Other service providers
    EventServiceProvider::class,
    ];
    }

    In The Ship

    Registering events and listeners in the Ship can be done by adding them to the listen array in the App\Ship\Providers\EventServiceProvider class.

    Events & Listeners Registration Flow

    If you are manually registering events and listeners and wish to understand the registration process, here is a breakdown of the registration flow.

    Consider the following folder structure:

    app
    ├── Containers
    │ └── Section
    │ └── Container
    │ ├── Events
    │ │ ├── DemoEvent.php ────►─┐
    │ │ └── ...
    │ ├── Listeners │
    │ │ ├── DemoListener.php ─►─┤
    │ │ └── ...
    │ └── Providers ▼
    │ ├── EventServiceProvider.php ─────────►─────────┐
    │ ├── MainServiceProvider.php ◄───registered─in─◄─┘
    │ └── ...
    └── Ship
    ├── Events
    │ ├── ShipDemoEvent.php ──►─┐
    │ └── ...
    ├── Listeners │
    │ ├── ShipDemoListener.php ►┤
    │ └── ...
    └── Providers ▼
    ├── EventServiceProvider.php ─────────►─────────┐
    ├── ShipProvider.php ◄───registered─in─◄─┘
    └── ...

    The following diagram illustrates the registration flow of events and listeners in the above folder structure:

    - + \ No newline at end of file diff --git a/docs/components/optional-components/factories/index.html b/docs/components/optional-components/factories/index.html index 22348d47b..7e8b10fc2 100644 --- a/docs/components/optional-components/factories/index.html +++ b/docs/components/optional-components/factories/index.html @@ -4,7 +4,7 @@ Factories | Apiato - + @@ -22,7 +22,7 @@ if your model does not extend the App\Ship\Parents\Models\Model or the App\Ship\Parents\Models\UserModel class, it is essential to include the ModelTrait trait in your model. By doing so, Apiato will be able to locate the appropriate factory and use it for the model when needed.

    use Apiato\Core\Traits\ModelTrait;

    class Demo
    {
    use ModelTrait;
    ...
    }
    - + \ No newline at end of file diff --git a/docs/components/optional-components/helpers/index.html b/docs/components/optional-components/helpers/index.html index 52bd06472..0c9eeae83 100644 --- a/docs/components/optional-components/helpers/index.html +++ b/docs/components/optional-components/helpers/index.html @@ -4,13 +4,13 @@ Helpers | Apiato - +
    Version: 12.x

    Helpers

    You have the option to create your own global "helper" PHP functions in designated directories, and Apiato will automatically autoload them for you.

    Deprecation Notice

    Please be aware that Container Helpers are deprecated and will be removed in the next major release.

    Rules

    • You MAY create as many helper files as you need per container.
    • All container-specific helpers MUST be placed in the app/Containers/{Section}/{Container}/Helpers directory.
    • All general helpers MUST be placed in the app/Ship/Helpers directory.

    Folder Structure

    app
    ├── Containers
    │ └── Section
    │ └── Container
    │ └── Helpers
    │ ├── helpers.php
    │ ├── mix.php
    │ └── ...
    └── Ship
    └── Helpers
    ├── another-helper.php
    ├── and-another.php
    └── ...

    Code Example

    if (!function_exists('add')) {
    function add(int $firstNumber, int $secondNumber): int
    {
    return $firstNumber + $secondNumber;
    }
    }
    - + \ No newline at end of file diff --git a/docs/components/optional-components/index.html b/docs/components/optional-components/index.html index 64ffc9ba6..deefd270e 100644 --- a/docs/components/optional-components/index.html +++ b/docs/components/optional-components/index.html @@ -4,7 +4,7 @@ Optional Components | Apiato - + @@ -14,7 +14,7 @@ Their usage is discretionary, depending on specific requirements.

    Most of these components are just Laravel components, and they function in the exact same way as Laravel components. However, they come with additional rules and conventions specific to Apiato.

    info

    To learn more about Apiato components, check the Components section.

    - + \ No newline at end of file diff --git a/docs/components/optional-components/jobs/index.html b/docs/components/optional-components/jobs/index.html index 9ce5baff5..5e40ff95c 100644 --- a/docs/components/optional-components/jobs/index.html +++ b/docs/components/optional-components/jobs/index.html @@ -4,7 +4,7 @@ Jobs | Apiato - + @@ -12,7 +12,7 @@
    Version: 12.x

    Jobs

    Apiato jobs are just Laravel Jobs, and they function in the exact same way as Laravel jobs. However, they come with additional rules and conventions specific to Apiato.

    To generate new jobs you may use the apiato:generate:job interactive command:

    php artisan apiato:generate:job

    Rules

    • All container-specific Jobs MUST be placed in the app/Containers/{Section}/{Container}/Jobs directory.
    • All general Jobs MUST be placed in the app/Ship/Jobs directory.
    • All Jobs MUST extend the App\Ship\Parents\Jobs\Job class.
      • The parent extension SHOULD be aliased as ParentJob.

    Folder Structure

    app
    ├── Containers
    │ └── Section
    │ └── Container
    │ └── Jobs
    │ ├── FooJob.php
    │ ├── BarJob.php
    │ └── ...
    └── Ship
    └── Jobs
    ├── BazJob.php
    └── ...

    Code Example

    Jobs are defined exactly as you would define them in Laravel.

    - + \ No newline at end of file diff --git a/docs/components/optional-components/mail/index.html b/docs/components/optional-components/mail/index.html index 2b0730352..add973e98 100644 --- a/docs/components/optional-components/mail/index.html +++ b/docs/components/optional-components/mail/index.html @@ -4,7 +4,7 @@ Mail | Apiato - + @@ -18,7 +18,7 @@ such as view('welcome'), will result in the template not being found.

    An exception to this namespace convention is for template files located in the app/Ship/Mails/Templates directory. These templates will be namespaced using the word ship instead of the Section and Container names.

    For example, you would access such a template like this: view(ship::welcome).

    - + \ No newline at end of file diff --git a/docs/components/optional-components/middlewares/index.html b/docs/components/optional-components/middlewares/index.html index 1aa0f86ae..eb95fff1b 100644 --- a/docs/components/optional-components/middlewares/index.html +++ b/docs/components/optional-components/middlewares/index.html @@ -4,7 +4,7 @@ Middlewares | Apiato - + @@ -19,7 +19,7 @@ you may use the apiato:generate:provider interactive command:

    php artisan apiato:generate:provider

    Remember to also register the MiddlewareServiceProvider in the container's MainServiceProvider:

    use ...
    use App\Ship\Parents\Providers\MainServiceProvider as ParentMainServiceProvider;

    class MainServiceProvider extends ParentMainServiceProvider
    {
    protected array $serviceProviders = [
    // ... Other service providers
    MiddlewareServiceProvider::class,
    ];
    }

    General Middlewares

    General middlewares must be registered in the App\Ship\Kernels\HttpKernel class.

    Third Party Middlewares

    When dealing with third-party packages that require middleware registration in the App\Ship\Kernels\HttpKernel class, you should follow these guidelines:

    • Specific Container Usage: If the package is used within a particular container, register its middleware in that container App\Containers\{Section}\{Container}\Providers\MiddlewareServiceProvider class.

    • Framework-wide Usage: If the package is generic and used throughout the entire application, you can register its middleware in the App\Ship\Kernels\HttpKernel class.

    Middleware Registration Flow

    If you want to understand the middleware registration process, here is a breakdown of the registration flow.

    Consider the following folder structure:

    app
    ├── Containers
    │ └── Section
    │ └── Container
    │ ├── Middlewares
    │ │ ├── DemoMiddleware.php ─►─┐
    │ │ └── ...
    │ └── Providers ▼
    │ ├── MiddlewareServiceProvider.php ─────►─────┐
    │ ├── MainServiceProvider.php ◄─registered─in─◄┘
    │ └── ...
    └── Ship
    ├── Kernels
    │ ├── HttpKernel.php ◄─registered─in─◄┐
    │ └── ...
    └── Middlewares │
    ├── AnotherMiddleware.php ─────►────┘
    └── ...

    The following diagram illustrates the registration flow of middlewares in the above folder structure:

    - + \ No newline at end of file diff --git a/docs/components/optional-components/migrations/index.html b/docs/components/optional-components/migrations/index.html index 28e7af182..6d44e04b7 100644 --- a/docs/components/optional-components/migrations/index.html +++ b/docs/components/optional-components/migrations/index.html @@ -4,7 +4,7 @@ Migrations | Apiato - + @@ -12,7 +12,7 @@
    Version: 12.x

    Migrations

    Apiato migrations are just Laravel Migrations, and they function in the exact same way as Laravel migrations. However, they come with additional rules and conventions specific to Apiato.

    To generate new migrations you may use the apiato:generate:migration interactive command:

    php artisan apiato:generate:migration

    Rules

    • All container-specific Migrations MUST be placed in the app/Containers/{Section}/{Container}/Data/Migrations directory.
    • All general Migrations MUST be placed in the app/Ship/Migrations directory.

    Folder Structure

    app
    ├── Containers
    │ └── Section
    │ └── Container
    │ └── Data
    │ └── Migrations
    │ ├── 0000_01_01_000001_create_things_table.php
    │ └── ...
    └── Ship
    └── Migrations
    ├── 0000_02_02_000002_create_another_things_table.php
    └── ...

    Code Example

    Migrations are defined exactly as you would define them in Laravel.

    - + \ No newline at end of file diff --git a/docs/components/optional-components/notifications/index.html b/docs/components/optional-components/notifications/index.html index 219d919e3..b511f9f18 100644 --- a/docs/components/optional-components/notifications/index.html +++ b/docs/components/optional-components/notifications/index.html @@ -4,7 +4,7 @@ Notifications | Apiato - + @@ -24,7 +24,7 @@ As a result, you don't need to manually generate the migration file. You can directly run the migrations using the php artisan migrate command, and the notifications table will be created for you.

    - + \ No newline at end of file diff --git a/docs/components/optional-components/policies/index.html b/docs/components/optional-components/policies/index.html index 57f545232..a5a43867e 100644 --- a/docs/components/optional-components/policies/index.html +++ b/docs/components/optional-components/policies/index.html @@ -4,7 +4,7 @@ Policies | Apiato - + @@ -21,7 +21,7 @@ Here is a breakdown of the registration flow.

    Consider the following folder structure:

    app
    └── Containers
    └── Section
    └── Container
    ├── Policies
    │ ├── DemoPolicy.php ─►─┐
    │ └── ...
    └── Providers ▼
    ├── AuthServiceProvider.php ─────────►───────┐
    ├── MainServiceProvider.php ◄─registered─in─◄┘
    └── ...

    The following diagram illustrates the registration flow of policies in the above folder structure:

    Helper Methods

    Available since Core v8.7.0

    All models are equipped with the owns and isOwnedBy methods, made available through the Apiato\Core\Traits\CanOwnTrait trait. These methods offer a convenient way to determine if a model is owned by another model or if a model owns another model.

    These methods support all types of relationships, as demonstrated below:

    // Check if a user owns a post
    $user->owns($post);

    // Check if a post is owned by a user
    $post->isOwnedBy($user);
    - + \ No newline at end of file diff --git a/docs/components/optional-components/repository/criterias/index.html b/docs/components/optional-components/repository/criterias/index.html index 148877029..1a4434a2b 100644 --- a/docs/components/optional-components/repository/criterias/index.html +++ b/docs/components/optional-components/repository/criterias/index.html @@ -4,7 +4,7 @@ Criterias | Apiato - + @@ -23,7 +23,7 @@ This approach offers the flexibility to create query conditions once and apply them consistently anywhere in your application, enhancing code reusability and maintainability.

    Rules

    • All container-specific Criterias MUST be placed in the app/Containers/{Section}/{Container}/Data/Criterias directory.
    • All general Criterias MUST be placed in the app/Ship/Criterias directory.
    • All Criterias MUST extend the App\Ship\Parents\Criterias\Criteria class.
      • The parent extension SHOULD be aliased as ParentCriteria.
    • Every Criteria MUST have an apply method.
    • A Criteria MUST not contain any extra code. If it needs data, the data MUST be passed to it.

    Folder Structure

    app
    ├── Containers
    │ └── Section
    │ └── Container
    │ └── Data
    │ └── Criterias
    │ ├── ColourRedCriteria.php
    │ ├── RaceCarsCriteria.php
    │ └── ...
    └── Ship
    └── Criterias
    ├── CreatedTodayCriteria.php
    ├── NotNullCriteria.php
    └── ...

    Code Example

    use App\Ship\Parents\Criterias\Criteria as ParentCriteria;
    use Prettus\Repository\Contracts\RepositoryInterface as PrettusRepositoryInterface;

    class IsNullCriteria extends ParentCriteria
    {
    public function __construct(
    private readonly string $field
    ) {
    }

    public function apply($model, PrettusRepositoryInterface $repository)
    {
    return $model->whereNull($this->field);
    }
    }

    Applying Criteria

    A Criteria can be applied to a Repository by using the pushCriteria method.

    public function __construct(
    protected readonly UserRepository $repository
    ) {
    }

    The pushCriteria method accepts an instance of a Criteria class or a string with the Criteria class name.

    public function run()
    {
    $this->repository->pushCriteria(new IsNullCriteria('email'));
    return $this->repository->paginate();
    }

    You can also apply multiple Criterias to a Repository by using the pushCriteria method multiple times.

    public function run()
    {
    $this->repository->pushCriteria(new IsNullCriteria('email'));
    $this->repository->pushCriteria(OrderByNameCriteria::class);
    return $this->repository->paginate();
    }
    - + \ No newline at end of file diff --git a/docs/components/optional-components/repository/repositories/index.html b/docs/components/optional-components/repository/repositories/index.html index ad4195194..e53e85a51 100644 --- a/docs/components/optional-components/repository/repositories/index.html +++ b/docs/components/optional-components/repository/repositories/index.html @@ -4,7 +4,7 @@ Repositories | Apiato - + @@ -58,7 +58,7 @@ findById
    getById
    findMany

    pushCriteriaWith

    This method is a wrapper around the pushCriteria method. It accepts data to be passed to the criteria class and allows for easier testing.

    findById

    This method is a wrapper around the find method. But it returns null if the record is not found.

    getById

    This method is a wrapper around the find method. But it throws a NotFoundException if the record is not found.

    findMany

    This method is a wrapper around the find method. But it returns an empty collection if no records are found.

    - + \ No newline at end of file diff --git a/docs/components/optional-components/seeders/index.html b/docs/components/optional-components/seeders/index.html index f595070a8..d6fb669e2 100644 --- a/docs/components/optional-components/seeders/index.html +++ b/docs/components/optional-components/seeders/index.html @@ -4,7 +4,7 @@ Seeders | Apiato - + @@ -25,7 +25,7 @@ You can locate this seeder class at app/Ship/Seeders/SeedDeploymentData.php. Similar to the testing seeder, the deployment seeder is not automatically loaded by Apiato. You can call this seeder and populate your database with production data by executing the following command:

    php artisan apiato:seed-deployment
    - + \ No newline at end of file diff --git a/docs/components/optional-components/service-providers/index.html b/docs/components/optional-components/service-providers/index.html index a6de240f4..18dcbdf7d 100644 --- a/docs/components/optional-components/service-providers/index.html +++ b/docs/components/optional-components/service-providers/index.html @@ -4,7 +4,7 @@ Service Providers | Apiato - + @@ -36,7 +36,7 @@ which makes it available.

    note

    Do note that the App\Ship\Parents\Providers\RouteServiceProvider is a unique case. Because it's required by Apiato, it is registered by the App\Ship\Prviders\ShipProvider and is loaded automatically.

    Service Providers Registration Flow

    If you want to understand the service provider registration process, here is a breakdown of the registration flow.

    Consider the following folder structure:

    app
    ├── Containers
    │ └── Section
    │ ├── ContainerA
    │ │ └── Providers
    │ │ ├── CustomServiceProvider.php ─────────►────────┐
    │ │ ├── EventServiceProvider.php ─────────►────────┤
    │ │ ├── MainServiceProvider.php ◄──registered─in─◄─┘
    │ │ └── ...
    │ └── ContainerB
    │ └── Providers
    │ ├── AnotherCustomServiceProvider.php ────────►────────┐
    │ ├── EventServiceProvider.php ────────►────────┤
    │ ├── MainServiceProvider.php ◄──registered─in─◄─┤
    │ ├── MiddlewareServiceProvider.php ────────►────────┘
    │ └── ...
    └── Ship
    └── Providers
    ├── CustomGeneralServiceProvider.php ────────►────────┐
    ├── RouteServiceProvider.php ────────►────────┤
    ├── ShipProvider.php ◄──registered─in─◄─┘
    └── ...

    The following diagram illustrates the registration flow of service providers in the above folder structure:

    - + \ No newline at end of file diff --git a/docs/components/optional-components/tests/index.html b/docs/components/optional-components/tests/index.html index 2174bdc87..a95b12702 100644 --- a/docs/components/optional-components/tests/index.html +++ b/docs/components/optional-components/tests/index.html @@ -4,7 +4,7 @@ Tests | Apiato - + @@ -118,7 +118,7 @@ Within this class, you can define the logic and data generation process for your testing data.

    Once you have defined your testing data, you can run the following command in your terminal:

    php artisan apiato:seed-test

    This command triggers the seeding process specifically for testing data, populating your application with the generated data.

    - + \ No newline at end of file diff --git a/docs/components/optional-components/values/index.html b/docs/components/optional-components/values/index.html index f217eb843..0071e081f 100644 --- a/docs/components/optional-components/values/index.html +++ b/docs/components/optional-components/values/index.html @@ -4,7 +4,7 @@ Values | Apiato - + @@ -15,7 +15,7 @@ Additionally, they do not possess functionality or modify any state; their sole purpose is to hold data.

    Value Objects are particularly well-suited for use with Laravel attributes casting, which allows us to cast a Value Object to a specific type, enabling seamless integration with Eloquent models and database operations.

    To generate new values you may use the apiato:generate:value interactive command:

    php artisan apiato:generate:value

    Rules

    • All container-specific Values MUST be placed in the app/Containers/{section}/{container}/Values directory.
    • All general Values MUST be placed in the app/Ship/Values directory.
    • All Values MUST extend the App\Ship\Parents\Values\Value class.
      • The parent extension SHOULD be aliased as ParentValue.

    Folder Structure

    app
    └── Containers
    └── Section
    └── Container
    └── Values
    ├── Output.php
    ├── Region.php
    └── ...

    Code Example

    class Location extends Value
    {
    public function __construct(
    public float $latitude,
    public float $longitude,
    ) {
    }
    }
    - + \ No newline at end of file diff --git a/docs/consulting/index.html b/docs/consulting/index.html index 50eb1602c..989d22aa2 100644 --- a/docs/consulting/index.html +++ b/docs/consulting/index.html @@ -4,13 +4,13 @@ Consulting | Apiato - +
    - + \ No newline at end of file diff --git a/docs/framework-features/api-versioning/index.html b/docs/framework-features/api-versioning/index.html index ed2463182..401787008 100644 --- a/docs/framework-features/api-versioning/index.html +++ b/docs/framework-features/api-versioning/index.html @@ -4,13 +4,13 @@ API Versioning | Apiato - +
    - + \ No newline at end of file diff --git a/docs/framework-features/code-generator/index.html b/docs/framework-features/code-generator/index.html index e82fa98b7..6205f576d 100644 --- a/docs/framework-features/code-generator/index.html +++ b/docs/framework-features/code-generator/index.html @@ -4,7 +4,7 @@ Code Generator | Apiato - + @@ -22,7 +22,7 @@ However, it is crucial to adhere to one essential rule:

    • The name of the file and the folder structure in app/Ship/Generators/CustomStubs MUST exactly match those in vendor/apiato/core/Generator/Stubs.

    To illustrate the process, let's assume you want to customize the creation of an action. Follow these steps:

    1. Locate the action.stub file in vendor/apiato/core/Generator/Stubs/actions.
    2. Copy the action.stub file and paste it into the app/Ship/Generators/CustomStubs/actions directory.
    3. Make the desired changes to the copied action.stub file according to your requirements.

    By completing these steps, whenever you run the php artisan apiato:generate:action command, your customized stub file will be employed instead of the default one, applying your modifications to the generated action files.

    - + \ No newline at end of file diff --git a/docs/framework-features/etag/index.html b/docs/framework-features/etag/index.html index 0dc6c5526..ec814d686 100644 --- a/docs/framework-features/etag/index.html +++ b/docs/framework-features/etag/index.html @@ -4,7 +4,7 @@ Etag | Apiato - + @@ -12,7 +12,7 @@
    Version: 12.x

    Etag

    The ETag or entity tag is part of HTTP, the protocol for the World Wide Web. It is one of several mechanisms that HTTP provides for Web cache validation, which allows a client to make conditional requests.

    You can read more about this feature in the Requests documentation.

    - + \ No newline at end of file diff --git a/docs/framework-features/index.html b/docs/framework-features/index.html index 4c36b100a..f60193905 100644 --- a/docs/framework-features/index.html +++ b/docs/framework-features/index.html @@ -4,13 +4,13 @@ Framework Features | Apiato - + - + \ No newline at end of file diff --git a/docs/framework-features/profiler/index.html b/docs/framework-features/profiler/index.html index 63432e02b..015149c5e 100644 --- a/docs/framework-features/profiler/index.html +++ b/docs/framework-features/profiler/index.html @@ -4,7 +4,7 @@ Profiler | Apiato - + @@ -17,7 +17,7 @@ Apiato employs the Apiato\Core\Middlewares\Http\ProfilerMiddleware to include the profiling data in the response.

    The profiler feature is initially disabled by default. To enable it, you should edit the .env file and set DEBUGBAR_ENABLED=true.

    To customize and manage the profiler response, you'll need to make adjustments in the configuration file located at app/Ship/Configs/debugbar.php.

    The following is an example of the profiler response:

    {
    "_profiler": {
    "__meta": {
    "id": "X167f293230e3457f1bbd95d9c82aba4a",
    "datetime": "2017-09-22 18:45:27",
    "utime": 1506105927.799299,
    "method": "GET",
    "uri": "/",
    "ip": "172.20.0.1"
    },
    "messages": {
    "count": 0,
    "messages": []
    },
    "time": {
    "start": 1506105922.742068,
    "end": 1506105927.799333,
    "duration": 5.057265043258667,
    "duration_str": "5.06s",
    "measures": [
    {
    "label": "Booting",
    "start": 1506105922.742068,
    "relative_start": 0,
    "end": 1506105923.524004,
    "relative_end": 1506105923.524004,
    "duration": 0.7819359302520752,
    "duration_str": "781.94ms",
    "params": [],
    "collector": null
    },
    {
    "label": "Application",
    "start": 1506105923.535343,
    "relative_start": 0.7932748794555664,
    "end": 1506105927.799336,
    "relative_end": 0.00000286102294921875,
    "duration": 4.26399302482605,
    "duration_str": "4.26s",
    "params": [],
    "collector": null
    }
    ]
    },
    "memory": {
    "peak_usage": 13234248,
    "peak_usage_str": "12.62MB"
    },
    "exceptions": {
    "count": 0,
    "exceptions": []
    },
    "route": {
    "uri": "GET /",
    "middleware": "api, throttle:30,1",
    "domain": "http://api.apiato.test",
    "as": "apis_root_page",
    "controller": "App\\Containers\\Welcome\\UI\\API\\Controllers\\Controller@apiRoot",
    "namespace": "App\\Containers\\Welcome\\UI\\API\\Controllers",
    "prefix": "/",
    "where": [],
    "file": "app/Containers/Welcome/UI/API/Controllers/Controller.php:20-25"
    },
    "queries": {
    "nb_statements": 0,
    "nb_failed_statements": 0,
    "accumulated_duration": 0,
    "accumulated_duration_str": "0μs",
    "statements": []
    },
    "logs": {
    "count": 3,
    "messages": [
    {
    "message": "...",
    "message_html": null,
    "is_string": false,
    "label": "error",
    "time": 1506105927.694807
    },
    {
    "message": "...",
    "message_html": null,
    "is_string": false,
    "label": "error",
    "time": 1506105927.694811
    },
    {
    "message": "[2017-09-18 17:38:15] testing.INFO: New User registration. ID = 970ylqvaogmxnbdr | Email = apiato@mail.test. Thank you for signing up.\n</div>\n</body>\n</html>\n \n",
    "message_html": null,
    "is_string": false,
    "label": "info",
    "time": 1506105927.694812
    }
    ]
    },
    "auth": {
    "guards": {
    "web": "array:2 [\n \"name\" => \"Guest\"\n \"user\" => array:1 [\n \"guest\" => true\n ]\n]",
    "api": "array:2 [\n \"name\" => \"Guest\"\n \"user\" => array:1 [\n \"guest\" => true\n ]\n]"
    },
    "names": ""
    },
    "gate": {
    "count": 0,
    "messages": []
    }
    }
    }
    - + \ No newline at end of file diff --git a/docs/framework-features/rate-limiting/index.html b/docs/framework-features/rate-limiting/index.html index 4ead90530..e68fd0fe5 100644 --- a/docs/framework-features/rate-limiting/index.html +++ b/docs/framework-features/rate-limiting/index.html @@ -4,7 +4,7 @@ Rate Limiting | Apiato - + @@ -17,7 +17,7 @@ You can disable it on specific endpoints or globally.

    On a specific endpoint

    Rate limiting can be disabled by removing the api middleware from an endpoint using withoutMiddleware('throttle:api') method. Read More.

    Globally

    To disable rate limiting completely, set GLOBAL_API_RATE_LIMIT_ENABLED to false in the .env file.

    - + \ No newline at end of file diff --git a/docs/framework-features/rbac/index.html b/docs/framework-features/rbac/index.html index 33804af9e..84c423f2d 100644 --- a/docs/framework-features/rbac/index.html +++ b/docs/framework-features/rbac/index.html @@ -4,7 +4,7 @@ Role Based Access Control | Apiato - + @@ -12,7 +12,7 @@
    - + \ No newline at end of file diff --git a/docs/getting-started/best-practices/index.html b/docs/getting-started/best-practices/index.html index 71654aa4b..10f782a9b 100644 --- a/docs/getting-started/best-practices/index.html +++ b/docs/getting-started/best-practices/index.html @@ -4,7 +4,7 @@ Best Practices | Apiato - + @@ -45,7 +45,7 @@ This gives maintainers of the API enough information to understand the problem that’s occurred. We don’t want errors to bring down our system, so we can leave them unhandled, which means that the API consumer has to handle them.

    Common error HTTP status codes include:

    • 200 OK Server successfully returned the requested data.
    • 201 CREATED Server successfully created or modified the requested resource.
    • 204 NO CONTENT Server successfully deleted the requested resource.
    • 400 INVALID REQUEST The request was invalid or cannot be served. The exact error should be explained in the error payload. E.g. „The JSON is not valid“.
    • 401 UNAUTHORIZED The request requires an user authentication.
    • 403 FORBIDDEN The server understood the request, but is refusing it or the access is not allowed.
    • 404 NOT FOUND There is no resource behind the URI.
    • 422 Unprocessable Entity Should be used if the server cannot process the enitity, e.g. if an image cannot be formatted or mandatory fields are missing in the payload.
    • 500 INTERNAL SERVER ERROR Internal Server Error.
    • 502 BAD GATEWAY Server received an invalid response from the upstream server while trying to fulfill the request.
    • 503 SERVICE UNAVAILABLE Service unavailable.

    Naming Conventions For Routes & Actions

    • ListResources: to fetch all resources.
    • FindResourceByID: to search for a single resource by its unique identifier.
    • CreateResource: to create a new resource.
    • UpdateResource: to update/edit existing resource.
    • DeleteResource: to delete a resource.
    - + \ No newline at end of file diff --git a/docs/getting-started/customized-laravel-components/index.html b/docs/getting-started/customized-laravel-components/index.html index 090286086..160f24988 100644 --- a/docs/getting-started/customized-laravel-components/index.html +++ b/docs/getting-started/customized-laravel-components/index.html @@ -4,14 +4,14 @@ Customized Laravel Components | Apiato - +
    Version: 12.x

    Customized Laravel Components

    Apiato provides a refined organization for Laravel default class locations. Here, you can find the default Laravel components and their corresponding locations within Apiato.

    Kernels

    • Http Kernel is moved from app/Http to app/Ship/Kernels and renamed to HttpKernel.

    • Console Kernel is moved from app/Console to app/Ship/Kernels and renamed to ConsoleKernel.

    Middlewares

    • Middlewares are moved from app/Http/Middleware to app/Ship/Middlewares.

    Handler

    • Exception Handler is moved from app/Exceptions to app/Ship/Exceptions/Handlers and renamed to ExceptionsHandler.

    Providers

    • For information about the new locations of Providers, please refer to this link.

    Routes

    Web and API

    Apiato introduces a new approach to route organization and does not use the default routes/web.php and routes/api.php files. Therefore, you won't find these files in Apiato. To learn more, please visit this link.

    Channels

    • The channels.php file has been relocated from routes to app/Ship/Broadcasts.

    Console

    • The console.php file has been moved from routes to app/Ship/Commands and renamed to closures.php.
    - + \ No newline at end of file diff --git a/docs/getting-started/installation/index.html b/docs/getting-started/installation/index.html index 1ef88377e..239f331aa 100644 --- a/docs/getting-started/installation/index.html +++ b/docs/getting-started/installation/index.html @@ -4,18 +4,18 @@ Installation | Apiato - +
    Version: 12.x

    Installation

    Your First Apiato Project

    Before creating your first Apiato project, you should ensure that your local machine has PHP and Composer installed. -If you are developing on macOS, PHP and Composer can be installed via Homebrew.

    After you have installed PHP and Composer, you may create a new Apiato project via the Composer create-project command:

    composer create-project apiato/apiato example-app

    Development Environment Setup

    You can run Apiato in any environment that you can run Laravel.

    tip

    Visit Laravel Installation for more details.

    Initial Configuration

    All the configuration files for the Laravel framework are stored in the config folder +If you are developing on macOS, PHP and Composer can be installed via Homebrew.

    After you have installed PHP and Composer, you may create a new Apiato project via the Composer create-project command:

    composer create-project apiato/apiato example-app --no-scripts

    Development Environment Setup

    You can run Apiato in any environment that you can run Laravel.

    tip

    Visit Laravel Installation for more details.

    Initial Configuration

    All the configuration files for the Laravel framework are stored in the config folder and all the configuration files for the Apiato framework are stored in app/Ship/Configs. Each option is documented, so feel free to look through the files and get familiar with the options available to you.

    Apiato needs almost no additional configuration out of the box. You are free to get started developing! However, you may wish to review the app/Ship/Configs/apiato.php file and its documentation. -It contains several options that you may wish to change according to your application.

    Environment Based Configuration

    Since many of Apiato configuration option values may vary +It contains several options that you may wish to change, according to your application.

    Environment Based Configuration

    Since many of Apiato configuration option values may vary depending on whether your application is running on your local machine or on a production web server, many important configuration values are defined using the .env file that exists at the root of your application.

    Your .env file should not be committed to your application's source control, since each developer / server using your application could require a different environment configuration. @@ -41,8 +41,8 @@ However, you can change this behavior.

    For example, if you'd like to achieve urls like apiato.test/api/, follow these steps:

    1. Open your .env file and modify the API domain by updating the API_URL value from http://api.apiato.test to http://apiato.test to remove the subdomain.
    2. In the app/Ship/Configs/apiato.php configuration file:
      • Set the prefix to api/.
      • Set enable_version_prefix to false.

    Generating API Documentation

    Apiato includes a convenient Documentation Generator package that utilizes ApiDocJs for API documentation generation.

    To get started, install ApiDocJs using NPM or your preferred dependency manager:

    npm install

    Next, generate the API documentation by executing the following command:

    php artisan apiato:apidoc

    Let's Play

    To witness Apiato in action, assuming you are using the default Subdomain and API Version Prefix configuration, you should be able to access the following URLs and see the following results:

    Web (Browser)

    API (HTTP Client)

    Next Steps

    Now that you have created your Apiato project, you may be wondering what to learn next. -If you're looking for a place to start, you should check out the following resources:

    - +If you're looking for a place to start, you should check out the following resources:

    + \ No newline at end of file diff --git a/docs/next/architecture-concepts/components/index.html b/docs/next/architecture-concepts/components/index.html index a11321585..b6e3b8f57 100644 --- a/docs/next/architecture-concepts/components/index.html +++ b/docs/next/architecture-concepts/components/index.html @@ -4,7 +4,7 @@ Components | Apiato - + @@ -19,7 +19,7 @@ simplifying future maintenance and facilitating modifications when needed.

    Components in Porto are categorized into two types: Main Components and Optional Components.

    Main Components

    Main Components are essential for the Container's functionality and must be used to achieve its core purpose.

    Optional Components

    Optional Components offer additional functionality that can be incorporated into the Container. Their usage is discretionary, depending on specific requirements.

    tip

    To learn more about how all this fits together, read the Request Lifecycle page.

    - + \ No newline at end of file diff --git a/docs/next/architecture-concepts/container/index.html b/docs/next/architecture-concepts/container/index.html index 7521269c2..758158401 100644 --- a/docs/next/architecture-concepts/container/index.html +++ b/docs/next/architecture-concepts/container/index.html @@ -4,7 +4,7 @@ Container | Apiato - + @@ -23,7 +23,7 @@ you may use the apiato:generate:container interactive command:

    php artisan apiato:generate:container

    Composer Dependencies

    To manage Composer dependencies, follow these guidelines:

    • All the Composer dependencies for a specific Container should be defined within that Container's composer.json file.
    • Dependencies related to the Ship layer should be placed in the root of the Ship layer, in a composer.json file.
    • Framework core dependencies should be defined in the project's root-level composer.json file.

    In practice, you can choose to place Composer dependencies in any of these composer.json files, and they will perform the same function. The choice of location depends on what is most relevant and convenient for your project.

    Readme

    Each Container has the option to include a readme.md file at its root, which serves to explain the Container's purpose and how to use it.

    To generate new readme files, you may use the apiato:generate:readme interactive command:

    php artisan apiato:generate:readme
    - + \ No newline at end of file diff --git a/docs/next/architecture-concepts/index.html b/docs/next/architecture-concepts/index.html index 8d345a64b..0b1570d16 100644 --- a/docs/next/architecture-concepts/index.html +++ b/docs/next/architecture-concepts/index.html @@ -4,7 +4,7 @@ Architecture Concepts | Apiato - + @@ -13,7 +13,7 @@ to structure the application code.

    Investing 30 minutes in reading the Porto Documentation before getting started is highly recommended and can prove to be a valuable use of your time. The document serves as a comprehensive guide and resource for understanding the Apiato project.

    - + \ No newline at end of file diff --git a/docs/next/architecture-concepts/porto/index.html b/docs/next/architecture-concepts/porto/index.html index 6291e439c..18d2427fe 100644 --- a/docs/next/architecture-concepts/porto/index.html +++ b/docs/next/architecture-concepts/porto/index.html @@ -4,7 +4,7 @@ Porto | Apiato - + @@ -18,7 +18,7 @@ It can be a specific feature or a wrapper around a RESTful API resource.

    note

    A Container is allowed to depend on other Containers in the same Section.

    Ship

    The Ship layer contains the infrastructure code, which consists of shared code utilized by all Containers.

    Typical Project Structure

    app
    ├── Containers
    │ ├── Section
    │ │ └── Container
    │ │ ├── Actions
    │ │ ├── Configs
    │ │ ├── Data
    │ │ │ ├── Factories
    │ │ │ ├── Migrations
    │ │ │ ├── Repositories
    │ │ │ └── Seeders
    │ │ ├── Mails
    │ │ │ └── Templates
    │ │ ├── Middlewares
    │ │ ├── Models
    │ │ ├── Notifications
    │ │ ├── Providers
    │ │ ├── Tasks
    │ │ ├── Tests
    │ │ ├── Traits
    │ │ └── UI
    │ │ ├── API
    │ │ │ ├── Controllers
    │ │ │ ├── Requests
    │ │ │ ├── Routes
    │ │ │ └── Transformers
    │ │ ├── WEB
    │ │ │ ├── Controllers
    │ │ │ ├── Requests
    │ │ │ ├── Routes
    │ │ │ └── Views
    │ │ └── CLI
    │ │ └── Commands
    │ └── Vendor `// All installed and reusable Containers`
    │ ├── ContainerA
    │ └── ContainerB
    └── Ship `// All shared code between all Containers`
    ├── Broadcasts
    ├── Commands
    ├── Configs
    ├── Contracts
    ├── Criterias
    ├── Events
    ├── Exceptions
    ├── Generators
    ├── Helpers
    ├── Kernels
    ├── Listeners
    ├── Mails
    ├── Middlewares
    ├── Migrations
    ├── Notifications
    ├── Parents
    ├── Providers
    ├── Seeders
    └── Tests

    Default Sections

    Apiato ships with two default Sections:

    • AppSection: contains all the default Containers.
    • Vendor: contains all the installed and reusable Containers.
    tip

    The Vendor section is a special Section within the Containers layer that holds installed and reusable Containers. It serves a similar purpose as the vendor folder located at the root. Any Section is permitted to depend on the Vendor Section, allowing for the utilization of its Containers.

    Read more about the Container Installer to learn how to install Vendor Containers.

    - + \ No newline at end of file diff --git a/docs/next/architecture-concepts/request-lifecycle/index.html b/docs/next/architecture-concepts/request-lifecycle/index.html index 93ab44124..6517de80a 100644 --- a/docs/next/architecture-concepts/request-lifecycle/index.html +++ b/docs/next/architecture-concepts/request-lifecycle/index.html @@ -4,7 +4,7 @@ Request Lifecycle | Apiato - + @@ -16,7 +16,7 @@ The Tasks can be used to execute reusable subsets of the business logic, with each Task responsible for a single portion of the main Action. The View or Transformer is used to build the response that is sent back to the User.

    Request Lifecycle Diagram

    Legend:

    • Solid Line: Mandatory dependency (always used)
    • Doted Line: Optional dependency (not always used)
    • Red Solid Border: Response generation
    • Green Dashed Border: Optional component (not always used)
    - + \ No newline at end of file diff --git a/docs/next/components/index.html b/docs/next/components/index.html index 59754b7ed..e4b744e44 100644 --- a/docs/next/components/index.html +++ b/docs/next/components/index.html @@ -4,7 +4,7 @@ Components | Apiato - + @@ -13,7 +13,7 @@ "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119.

    info

    To learn more about Apiato components, check the Components section.

    - + \ No newline at end of file diff --git a/docs/next/components/main-components/actions/index.html b/docs/next/components/main-components/actions/index.html index df04f6389..509fcd73f 100644 --- a/docs/next/components/main-components/actions/index.html +++ b/docs/next/components/main-components/actions/index.html @@ -4,7 +4,7 @@ Actions | Apiato - + @@ -20,7 +20,7 @@ However, it's important to note that not all operations may be automatically rolled back. For example, file system operations, such as uploading an image, are typically not covered by the database transaction and would need to be handled manually.

    - + \ No newline at end of file diff --git a/docs/next/components/main-components/controllers/index.html b/docs/next/components/main-components/controllers/index.html index cd059aa9c..06d5c20de 100644 --- a/docs/next/components/main-components/controllers/index.html +++ b/docs/next/components/main-components/controllers/index.html @@ -4,7 +4,7 @@ Controllers | Apiato - + @@ -16,7 +16,7 @@ and it MUST be used in conjunction with the transform method. This is different from the meta parameter in the transform method. This metadata will be returned directly under the meta key.

    You can use this method in conjunction with the meta parameter in the transform method.

    $metaData = ['foo' => 999, 'bar'];

    $this->withMeta($metaData)->transform($sample, SampleTransformer::class, meta: ['foo' => 'bar', 'baz' => 1]);

    // Response
    {
    "data": {},
    "meta": {
    "foo": 999,
    "0": "bar",
    "include": [...],
    "custom": {
    "foo": "bar",
    "baz": 1
    },
    "pagination": {}
    }
    }

    json

    This method allows you to pass an array of data that will be represented as JSON.

    $this->json($data)

    created

    This method allows you to return a response with a 201 status code.

    $this->created($data)

    deleted

    This method allows you to return a response with a 202 status code.

    $this->deleted($deletedModel)

    // Response
    {
    "message": "Model (1) Deleted Successfully."
    }

    accepted

    This method allows you to return a response with a 202 status code.

    $this->accepted($data)

    noContent

    This method allows you to return a response with a 204 status code.

    $this->noContent()
    - + \ No newline at end of file diff --git a/docs/next/components/main-components/exceptions/index.html b/docs/next/components/main-components/exceptions/index.html index f6ea6ac2c..69e5a505b 100644 --- a/docs/next/components/main-components/exceptions/index.html +++ b/docs/next/components/main-components/exceptions/index.html @@ -4,7 +4,7 @@ Exceptions | Apiato - + @@ -13,7 +13,7 @@ Translation strings are automatically translated if the translations are found. To handle localization, you can use the Localization Container.

    // Example 1
    throw (new AccountFailedException())->withErrors(['email' => 'appSection@user::exceptions.email-taken']);
    // Example 2
    throw (new AccountFailedException())->withErrors(['email' => 'appSection@user::exceptions.email-taken', 'Another not translated message']);

    Response:

    {
    "message": "The exception error message.",
    "errors": {
    "email": [
    "The email has already been taken.",
    "Another not translated message"
    ]
    }
    }

    debug

    The debug method is used for logging error messages during debugging and development. The debug method accepts string or \Exception instance

    throw (new AccountFailedException())->debug($e);
    - + \ No newline at end of file diff --git a/docs/next/components/main-components/index.html b/docs/next/components/main-components/index.html index 8b3939be7..f6e5e87f4 100644 --- a/docs/next/components/main-components/index.html +++ b/docs/next/components/main-components/index.html @@ -4,13 +4,13 @@ Main Components | Apiato - +
    - + \ No newline at end of file diff --git a/docs/next/components/main-components/models/index.html b/docs/next/components/main-components/models/index.html index 8ab6b09d2..31409bfc6 100644 --- a/docs/next/components/main-components/models/index.html +++ b/docs/next/components/main-components/models/index.html @@ -4,7 +4,7 @@ Models | Apiato - + @@ -16,7 +16,7 @@ it is essential to incorporate the ModelTrait trait into your model. By doing so, your model will benefit from various functionalities provided by the trait, such as hash ids and other features necessary for proper integration with the framework.

    use Apiato\Core\Traits\ModelTrait;

    class Demo
    {
    use ModelTrait;
    ...
    }
    - + \ No newline at end of file diff --git a/docs/next/components/main-components/requests/index.html b/docs/next/components/main-components/requests/index.html index 0a91f3493..5a57a9bf1 100644 --- a/docs/next/components/main-components/requests/index.html +++ b/docs/next/components/main-components/requests/index.html @@ -4,7 +4,7 @@ Requests | Apiato - + @@ -73,7 +73,7 @@ which employs the Shallow technique. This middleware can be particularly valuable in reducing bandwidth usage for clients, especially on mobile devices.

    Please note that this feature is disabled by default. To enable it, follow these steps:

    1. Navigate to the app/Ship/Configs/apiato.php configuration file.
    2. Inside the configuration file, locate the use-etag configuration parameter.
    3. Set the use-etag parameter to true.

    Keep in mind that for this feature to function correctly, the client must include the If-None-Match HTTP header, which corresponds to the ETag value, in their request.

    - + \ No newline at end of file diff --git a/docs/next/components/main-components/routes/index.html b/docs/next/components/main-components/routes/index.html index 7a5268cd9..6df5d9b93 100644 --- a/docs/next/components/main-components/routes/index.html +++ b/docs/next/components/main-components/routes/index.html @@ -4,7 +4,7 @@ Routes | Apiato - + @@ -18,7 +18,7 @@ Maintaining this distinction enables the generation of separate documentations for each type, ensuring that your internal API remains private and secure. This feature can be configured through the Documentation Generator package.

    Public Routes:

    • Accessible to third parties.
    • May or may not require authentication.

    Private Routes:

    • Accessible only to your own apps.
    • May or may not require authentication.
    - + \ No newline at end of file diff --git a/docs/next/components/main-components/subactions/index.html b/docs/next/components/main-components/subactions/index.html index 0dc212b96..93ccdd7b4 100644 --- a/docs/next/components/main-components/subactions/index.html +++ b/docs/next/components/main-components/subactions/index.html @@ -4,7 +4,7 @@ Sub Actions | Apiato - + @@ -13,7 +13,7 @@ They enable Actions to share a sequence of Tasks, thus promoting reusability. Similar to how Tasks enable Actions to share specific functionalities, SubActions serve to share a predefined set of Tasks.

    All the features and capabilities available for regular Actions are also applicable to SubActions.

    To generate new SubActions you may use the apiato:generate:subaction interactive command:

    php artisan apiato:generate:subaction

    Definition & Principles

    Read Porto SAP Documentation (#Sub-Actions).

    Rules

    • All SubActions:
      • MUST be placed in the app/Containers/{Section}/{Container}/Actions directory.
      • MUST extend the App\Ship\Parents\Actions\SubAction class.
        • The parent extension SHOULD be aliased as ParentSubAction.

    Folder Structure

    app
    └── Containers
    └── Section
    └── Container
    └── Actions
    ├── ValidateAddressSubAction.php
    ├── BuildOrderSubAction.php
    └── ...

    Code Example

    use ...
    use App\Ship\Parents\Actions\SubAction as ParentSubAction;

    class DemoSubAction extends ParentSubAction
    {
    public function __construct(
    private readonly DemoTask $demoTask
    ) {
    }

    public function run(array $data)
    {
    return $this->demoTask->run($data);
    }
    }
    - + \ No newline at end of file diff --git a/docs/next/components/main-components/tasks/index.html b/docs/next/components/main-components/tasks/index.html index 57fcf1788..aa5039a68 100644 --- a/docs/next/components/main-components/tasks/index.html +++ b/docs/next/components/main-components/tasks/index.html @@ -4,7 +4,7 @@ Tasks | Apiato - + @@ -15,7 +15,7 @@ in encapsulating functionalities that are utilized by multiple Actions spanning various Containers within your application.

    To generate new tasks you may use the apiato:generate:task interactive command:

    php artisan apiato:generate:task

    Additionally, to retrieve a list of the existing tasks in your Apiato application, use the apiato:list:tasks command.

    php artisan apiato:list:tasks

    Definition & Principles

    Read Porto SAP Documentation (#Tasks).

    Rules

    • All Tasks:
      • MUST be placed in the app/Containers/{Section}/{Container}/Tasks directory.
      • MUST extend the App\Ship\Parents\Tasks\Task class.
        • The parent extension SHOULD be aliased as ParentTask.

    Folder Structure

    app
    └── Containers
    └── Section
    └── Container
    └── Tasks
    ├── CreateResourceTask.php
    ├── DeleteResourceTask.php
    └── ...

    Code Example

    use ...
    use App\Ship\Parents\Tasks\Task as ParentTask;

    class DemoTask extends ParentTask
    {
    public function run(int $a, int $b): int
    {
    return $a + $b;
    }
    }
    - + \ No newline at end of file diff --git a/docs/next/components/main-components/transformers/index.html b/docs/next/components/main-components/transformers/index.html index 62c42ee9a..ed149919b 100644 --- a/docs/next/components/main-components/transformers/index.html +++ b/docs/next/components/main-components/transformers/index.html @@ -4,7 +4,7 @@ Transformers | Apiato - + @@ -54,7 +54,7 @@ This serializer is not to everyone’s tastes, because it adds a data namespace to the output. A very basic response of the DataArraySerializer will look like this:

    {
    "data": {
    "object": "User",
    "id": "XbPW7awNkzl83LD6",
    "name": "Mohammad Alavi"
    }
    }

    The DataArraySerializer is handy because it allows space for meta data (like pagination, or totals) in both Items and Collections.

    {
    "data": [ ... ],
    "meta": {
    "include": [
    "xxx",
    "yyy"
    ],
    "custom": [],
    "pagination": {
    "total": 999,
    "count": 999,
    "per_page": 999,
    "current_page": 999,
    "total_pages": 999,
    "links": {
    "next": "http://api.apiato.test/v1/accounts?page=999"
    }
    }
    }
    }
    Further Reading

    For more detailed information, please refer to Fractal and Laravel Fractal Wrapper documentations.

    - + \ No newline at end of file diff --git a/docs/next/components/main-components/views/index.html b/docs/next/components/main-components/views/index.html index 785d4ff85..4461db7e8 100644 --- a/docs/next/components/main-components/views/index.html +++ b/docs/next/components/main-components/views/index.html @@ -4,7 +4,7 @@ Views | Apiato - + @@ -17,7 +17,7 @@ such as view('welcome-page'), will result in the view not being found.

    An exception to this namespace convention is for view files located in the app/Ship/Views and app/Ship/Mails/Templates directories. These views will be namespaced using the word ship instead of the Section and Container names.

    For example, you would access such a view like this: view(ship::welcome-page).

    - + \ No newline at end of file diff --git a/docs/next/components/optional-components/commands/index.html b/docs/next/components/optional-components/commands/index.html index 86f83a1b3..247367e7a 100644 --- a/docs/next/components/optional-components/commands/index.html +++ b/docs/next/components/optional-components/commands/index.html @@ -4,7 +4,7 @@ Commands | Apiato - + @@ -12,7 +12,7 @@
    Version: Next 🚧

    Commands

    Apiato commands are just Laravel Commands, and they function in the exact same way as Laravel commands. However, they come with additional rules and conventions specific to Apiato.

    Rules

    • All container-specific Commands MUST be placed in the app/Containers/{Section}/{Container}/UI/CLI/Commands directory.
    • All general Commands MUST be placed in the app/Ship/Commands directory.
    • All Commands:
      • MUST extend the App\Ship\Parents\Commands\ConsoleCommand class.
        • The parent extension SHOULD be aliased as ConsoleCommand.
      • SHOULD call an Action to perform its job, and SHOULD NOT contain any business logic.

    Folder Structure

    app
    ├── Containers
    │ └── Section
    │ └── Container
    │ └── UI
    │ └── CLI
    │ └── Commands
    │ ├── FirstCommand.php
    │ ├── SecondCommand.php
    │ └── ...
    └── Ship
    └── Commands
    ├── FirstCommand.php
    ├── SecondCommand.php
    └── ...

    Code Example

    Commands are defined exactly as you would define them in Laravel.

    Closure Commands

    You can define your console closure commands in app/Ship/Commands/closures.php.

    - + \ No newline at end of file diff --git a/docs/next/components/optional-components/configs/index.html b/docs/next/components/optional-components/configs/index.html index 37d83debd..10c42e01b 100644 --- a/docs/next/components/optional-components/configs/index.html +++ b/docs/next/components/optional-components/configs/index.html @@ -4,7 +4,7 @@ Configs | Apiato - + @@ -17,7 +17,7 @@ camelCase representation of the container's Section name, succeeded by -, and then the camelCase representation of the Container name.

    For instance, if you have a container named "MyContainer" within the "MySection" section, the configuration file would be named mySection-myContainer.php.

    - + \ No newline at end of file diff --git a/docs/next/components/optional-components/events/index.html b/docs/next/components/optional-components/events/index.html index 9adc9db44..73c29a104 100644 --- a/docs/next/components/optional-components/events/index.html +++ b/docs/next/components/optional-components/events/index.html @@ -4,7 +4,7 @@ Events | Apiato - + @@ -17,7 +17,7 @@ you may use the apiato:generate:provider interactive command:

    php artisan apiato:generate:provider

    Remember to also register the EventServiceProvider in the container's MainServiceProvider:

    use ...
    use App\Ship\Parents\Providers\MainServiceProvider as ParentMainServiceProvider;

    class MainServiceProvider extends ParentMainServiceProvider
    {
    protected array $serviceProviders = [
    // ... Other service providers
    EventServiceProvider::class,
    ];
    }

    In The Ship

    Registering events and listeners in the Ship can be done by adding them to the listen array in the App\Ship\Providers\EventServiceProvider class.

    Events & Listeners Registration Flow

    If you are manually registering events and listeners and wish to understand the registration process, here is a breakdown of the registration flow.

    Consider the following folder structure:

    app
    ├── Containers
    │ └── Section
    │ └── Container
    │ ├── Events
    │ │ ├── DemoEvent.php ────►─┐
    │ │ └── ...
    │ ├── Listeners │
    │ │ ├── DemoListener.php ─►─┤
    │ │ └── ...
    │ └── Providers ▼
    │ ├── EventServiceProvider.php ─────────►─────────┐
    │ ├── MainServiceProvider.php ◄───registered─in─◄─┘
    │ └── ...
    └── Ship
    ├── Events
    │ ├── ShipDemoEvent.php ──►─┐
    │ └── ...
    ├── Listeners │
    │ ├── ShipDemoListener.php ►┤
    │ └── ...
    └── Providers ▼
    ├── EventServiceProvider.php ─────────►─────────┐
    ├── ShipProvider.php ◄───registered─in─◄─┘
    └── ...

    The following diagram illustrates the registration flow of events and listeners in the above folder structure:

    - + \ No newline at end of file diff --git a/docs/next/components/optional-components/factories/index.html b/docs/next/components/optional-components/factories/index.html index b476da7b5..d8c904044 100644 --- a/docs/next/components/optional-components/factories/index.html +++ b/docs/next/components/optional-components/factories/index.html @@ -4,7 +4,7 @@ Factories | Apiato - + @@ -22,7 +22,7 @@ if your model does not extend the App\Ship\Parents\Models\Model or the App\Ship\Parents\Models\UserModel class, it is essential to include the ModelTrait trait in your model. By doing so, Apiato will be able to locate the appropriate factory and use it for the model when needed.

    use Apiato\Core\Traits\ModelTrait;

    class Demo
    {
    use ModelTrait;
    ...
    }
    - + \ No newline at end of file diff --git a/docs/next/components/optional-components/helpers/index.html b/docs/next/components/optional-components/helpers/index.html index 0e67cd992..d7b8d26e9 100644 --- a/docs/next/components/optional-components/helpers/index.html +++ b/docs/next/components/optional-components/helpers/index.html @@ -4,13 +4,13 @@ Helpers | Apiato - +
    Version: Next 🚧

    Helpers

    You have the option to create your own global "helper" PHP functions in designated directories, and Apiato will automatically autoload them for you.

    Deprecation Notice

    Please be aware that Container Helpers are deprecated and will be removed in the next major release.

    Rules

    • You MAY create as many helper files as you need per container.
    • All container-specific helpers MUST be placed in the app/Containers/{Section}/{Container}/Helpers directory.
    • All general helpers MUST be placed in the app/Ship/Helpers directory.

    Folder Structure

    app
    ├── Containers
    │ └── Section
    │ └── Container
    │ └── Helpers
    │ ├── helpers.php
    │ ├── mix.php
    │ └── ...
    └── Ship
    └── Helpers
    ├── another-helper.php
    ├── and-another.php
    └── ...

    Code Example

    if (!function_exists('add')) {
    function add(int $firstNumber, int $secondNumber): int
    {
    return $firstNumber + $secondNumber;
    }
    }
    - + \ No newline at end of file diff --git a/docs/next/components/optional-components/index.html b/docs/next/components/optional-components/index.html index 710c12126..2d7acf13d 100644 --- a/docs/next/components/optional-components/index.html +++ b/docs/next/components/optional-components/index.html @@ -4,7 +4,7 @@ Optional Components | Apiato - + @@ -14,7 +14,7 @@ Their usage is discretionary, depending on specific requirements.

    Most of these components are just Laravel components, and they function in the exact same way as Laravel components. However, they come with additional rules and conventions specific to Apiato.

    info

    To learn more about Apiato components, check the Components section.

    - + \ No newline at end of file diff --git a/docs/next/components/optional-components/jobs/index.html b/docs/next/components/optional-components/jobs/index.html index be1a177c7..6f758e2af 100644 --- a/docs/next/components/optional-components/jobs/index.html +++ b/docs/next/components/optional-components/jobs/index.html @@ -4,7 +4,7 @@ Jobs | Apiato - + @@ -12,7 +12,7 @@
    Version: Next 🚧

    Jobs

    Apiato jobs are just Laravel Jobs, and they function in the exact same way as Laravel jobs. However, they come with additional rules and conventions specific to Apiato.

    To generate new jobs you may use the apiato:generate:job interactive command:

    php artisan apiato:generate:job

    Rules

    • All container-specific Jobs MUST be placed in the app/Containers/{Section}/{Container}/Jobs directory.
    • All general Jobs MUST be placed in the app/Ship/Jobs directory.
    • All Jobs MUST extend the App\Ship\Parents\Jobs\Job class.
      • The parent extension SHOULD be aliased as ParentJob.

    Folder Structure

    app
    ├── Containers
    │ └── Section
    │ └── Container
    │ └── Jobs
    │ ├── FooJob.php
    │ ├── BarJob.php
    │ └── ...
    └── Ship
    └── Jobs
    ├── BazJob.php
    └── ...

    Code Example

    Jobs are defined exactly as you would define them in Laravel.

    - + \ No newline at end of file diff --git a/docs/next/components/optional-components/mail/index.html b/docs/next/components/optional-components/mail/index.html index aa110250d..91994daf8 100644 --- a/docs/next/components/optional-components/mail/index.html +++ b/docs/next/components/optional-components/mail/index.html @@ -4,7 +4,7 @@ Mail | Apiato - + @@ -18,7 +18,7 @@ such as view('welcome'), will result in the template not being found.

    An exception to this namespace convention is for template files located in the app/Ship/Mails/Templates directory. These templates will be namespaced using the word ship instead of the Section and Container names.

    For example, you would access such a template like this: view(ship::welcome).

    - + \ No newline at end of file diff --git a/docs/next/components/optional-components/middlewares/index.html b/docs/next/components/optional-components/middlewares/index.html index 852a0c94a..2849357ca 100644 --- a/docs/next/components/optional-components/middlewares/index.html +++ b/docs/next/components/optional-components/middlewares/index.html @@ -4,7 +4,7 @@ Middlewares | Apiato - + @@ -19,7 +19,7 @@ you may use the apiato:generate:provider interactive command:

    php artisan apiato:generate:provider

    Remember to also register the MiddlewareServiceProvider in the container's MainServiceProvider:

    use ...
    use App\Ship\Parents\Providers\MainServiceProvider as ParentMainServiceProvider;

    class MainServiceProvider extends ParentMainServiceProvider
    {
    protected array $serviceProviders = [
    // ... Other service providers
    MiddlewareServiceProvider::class,
    ];
    }

    General Middlewares

    General middlewares must be registered in the App\Ship\Kernels\HttpKernel class.

    Third Party Middlewares

    When dealing with third-party packages that require middleware registration in the App\Ship\Kernels\HttpKernel class, you should follow these guidelines:

    • Specific Container Usage: If the package is used within a particular container, register its middleware in that container App\Containers\{Section}\{Container}\Providers\MiddlewareServiceProvider class.

    • Framework-wide Usage: If the package is generic and used throughout the entire application, you can register its middleware in the App\Ship\Kernels\HttpKernel class.

    Middleware Registration Flow

    If you want to understand the middleware registration process, here is a breakdown of the registration flow.

    Consider the following folder structure:

    app
    ├── Containers
    │ └── Section
    │ └── Container
    │ ├── Middlewares
    │ │ ├── DemoMiddleware.php ─►─┐
    │ │ └── ...
    │ └── Providers ▼
    │ ├── MiddlewareServiceProvider.php ─────►─────┐
    │ ├── MainServiceProvider.php ◄─registered─in─◄┘
    │ └── ...
    └── Ship
    ├── Kernels
    │ ├── HttpKernel.php ◄─registered─in─◄┐
    │ └── ...
    └── Middlewares │
    ├── AnotherMiddleware.php ─────►────┘
    └── ...

    The following diagram illustrates the registration flow of middlewares in the above folder structure:

    - + \ No newline at end of file diff --git a/docs/next/components/optional-components/migrations/index.html b/docs/next/components/optional-components/migrations/index.html index 73cc69c4d..da1b1854c 100644 --- a/docs/next/components/optional-components/migrations/index.html +++ b/docs/next/components/optional-components/migrations/index.html @@ -4,7 +4,7 @@ Migrations | Apiato - + @@ -12,7 +12,7 @@
    Version: Next 🚧

    Migrations

    Apiato migrations are just Laravel Migrations, and they function in the exact same way as Laravel migrations. However, they come with additional rules and conventions specific to Apiato.

    To generate new migrations you may use the apiato:generate:migration interactive command:

    php artisan apiato:generate:migration

    Rules

    • All container-specific Migrations MUST be placed in the app/Containers/{Section}/{Container}/Data/Migrations directory.
    • All general Migrations MUST be placed in the app/Ship/Migrations directory.

    Folder Structure

    app
    ├── Containers
    │ └── Section
    │ └── Container
    │ └── Data
    │ └── Migrations
    │ ├── 0000_01_01_000001_create_things_table.php
    │ └── ...
    └── Ship
    └── Migrations
    ├── 0000_02_02_000002_create_another_things_table.php
    └── ...

    Code Example

    Migrations are defined exactly as you would define them in Laravel.

    - + \ No newline at end of file diff --git a/docs/next/components/optional-components/notifications/index.html b/docs/next/components/optional-components/notifications/index.html index 531d9f138..1e1c3f271 100644 --- a/docs/next/components/optional-components/notifications/index.html +++ b/docs/next/components/optional-components/notifications/index.html @@ -4,7 +4,7 @@ Notifications | Apiato - + @@ -24,7 +24,7 @@ As a result, you don't need to manually generate the migration file. You can directly run the migrations using the php artisan migrate command, and the notifications table will be created for you.

    - + \ No newline at end of file diff --git a/docs/next/components/optional-components/policies/index.html b/docs/next/components/optional-components/policies/index.html index 8c87db7d0..d7326072e 100644 --- a/docs/next/components/optional-components/policies/index.html +++ b/docs/next/components/optional-components/policies/index.html @@ -4,7 +4,7 @@ Policies | Apiato - + @@ -21,7 +21,7 @@ Here is a breakdown of the registration flow.

    Consider the following folder structure:

    app
    └── Containers
    └── Section
    └── Container
    ├── Policies
    │ ├── DemoPolicy.php ─►─┐
    │ └── ...
    └── Providers ▼
    ├── AuthServiceProvider.php ─────────►───────┐
    ├── MainServiceProvider.php ◄─registered─in─◄┘
    └── ...

    The following diagram illustrates the registration flow of policies in the above folder structure:

    Helper Methods

    Available since Core v8.7.0

    All models are equipped with the owns and isOwnedBy methods, made available through the Apiato\Core\Traits\CanOwnTrait trait. These methods offer a convenient way to determine if a model is owned by another model or if a model owns another model.

    These methods support all types of relationships, as demonstrated below:

    // Check if a user owns a post
    $user->owns($post);

    // Check if a post is owned by a user
    $post->isOwnedBy($user);
    - + \ No newline at end of file diff --git a/docs/next/components/optional-components/repository/criterias/index.html b/docs/next/components/optional-components/repository/criterias/index.html index d894631bc..db95c191e 100644 --- a/docs/next/components/optional-components/repository/criterias/index.html +++ b/docs/next/components/optional-components/repository/criterias/index.html @@ -4,7 +4,7 @@ Criterias | Apiato - + @@ -23,7 +23,7 @@ This approach offers the flexibility to create query conditions once and apply them consistently anywhere in your application, enhancing code reusability and maintainability.

    Rules

    • All container-specific Criterias MUST be placed in the app/Containers/{Section}/{Container}/Data/Criterias directory.
    • All general Criterias MUST be placed in the app/Ship/Criterias directory.
    • All Criterias MUST extend the App\Ship\Parents\Criterias\Criteria class.
      • The parent extension SHOULD be aliased as ParentCriteria.
    • Every Criteria MUST have an apply method.
    • A Criteria MUST not contain any extra code. If it needs data, the data MUST be passed to it.

    Folder Structure

    app
    ├── Containers
    │ └── Section
    │ └── Container
    │ └── Data
    │ └── Criterias
    │ ├── ColourRedCriteria.php
    │ ├── RaceCarsCriteria.php
    │ └── ...
    └── Ship
    └── Criterias
    ├── CreatedTodayCriteria.php
    ├── NotNullCriteria.php
    └── ...

    Code Example

    use App\Ship\Parents\Criterias\Criteria as ParentCriteria;
    use Prettus\Repository\Contracts\RepositoryInterface as PrettusRepositoryInterface;

    class IsNullCriteria extends ParentCriteria
    {
    public function __construct(
    private readonly string $field
    ) {
    }

    public function apply($model, PrettusRepositoryInterface $repository)
    {
    return $model->whereNull($this->field);
    }
    }

    Applying Criteria

    A Criteria can be applied to a Repository by using the pushCriteria method.

    public function __construct(
    protected readonly UserRepository $repository
    ) {
    }

    The pushCriteria method accepts an instance of a Criteria class or a string with the Criteria class name.

    public function run()
    {
    $this->repository->pushCriteria(new IsNullCriteria('email'));
    return $this->repository->paginate();
    }

    You can also apply multiple Criterias to a Repository by using the pushCriteria method multiple times.

    public function run()
    {
    $this->repository->pushCriteria(new IsNullCriteria('email'));
    $this->repository->pushCriteria(OrderByNameCriteria::class);
    return $this->repository->paginate();
    }
    - + \ No newline at end of file diff --git a/docs/next/components/optional-components/repository/repositories/index.html b/docs/next/components/optional-components/repository/repositories/index.html index 404cd672f..a798fb5d3 100644 --- a/docs/next/components/optional-components/repository/repositories/index.html +++ b/docs/next/components/optional-components/repository/repositories/index.html @@ -4,7 +4,7 @@ Repositories | Apiato - + @@ -58,7 +58,7 @@ findById
    getById
    findMany

    pushCriteriaWith

    This method is a wrapper around the pushCriteria method. It accepts data to be passed to the criteria class and allows for easier testing.

    findById

    This method is a wrapper around the find method. But it returns null if the record is not found.

    getById

    This method is a wrapper around the find method. But it throws a NotFoundException if the record is not found.

    findMany

    This method is a wrapper around the find method. But it returns an empty collection if no records are found.

    - + \ No newline at end of file diff --git a/docs/next/components/optional-components/seeders/index.html b/docs/next/components/optional-components/seeders/index.html index 77fa2cdec..466b8d180 100644 --- a/docs/next/components/optional-components/seeders/index.html +++ b/docs/next/components/optional-components/seeders/index.html @@ -4,7 +4,7 @@ Seeders | Apiato - + @@ -25,7 +25,7 @@ You can locate this seeder class at app/Ship/Seeders/SeedDeploymentData.php. Similar to the testing seeder, the deployment seeder is not automatically loaded by Apiato. You can call this seeder and populate your database with production data by executing the following command:

    php artisan apiato:seed-deployment
    - + \ No newline at end of file diff --git a/docs/next/components/optional-components/service-providers/index.html b/docs/next/components/optional-components/service-providers/index.html index 24d3a6b05..d54a491db 100644 --- a/docs/next/components/optional-components/service-providers/index.html +++ b/docs/next/components/optional-components/service-providers/index.html @@ -4,7 +4,7 @@ Service Providers | Apiato - + @@ -36,7 +36,7 @@ which makes it available.

    note

    Do note that the App\Ship\Parents\Providers\RouteServiceProvider is a unique case. Because it's required by Apiato, it is registered by the App\Ship\Prviders\ShipProvider and is loaded automatically.

    Service Providers Registration Flow

    If you want to understand the service provider registration process, here is a breakdown of the registration flow.

    Consider the following folder structure:

    app
    ├── Containers
    │ └── Section
    │ ├── ContainerA
    │ │ └── Providers
    │ │ ├── CustomServiceProvider.php ─────────►────────┐
    │ │ ├── EventServiceProvider.php ─────────►────────┤
    │ │ ├── MainServiceProvider.php ◄──registered─in─◄─┘
    │ │ └── ...
    │ └── ContainerB
    │ └── Providers
    │ ├── AnotherCustomServiceProvider.php ────────►────────┐
    │ ├── EventServiceProvider.php ────────►────────┤
    │ ├── MainServiceProvider.php ◄──registered─in─◄─┤
    │ ├── MiddlewareServiceProvider.php ────────►────────┘
    │ └── ...
    └── Ship
    └── Providers
    ├── CustomGeneralServiceProvider.php ────────►────────┐
    ├── RouteServiceProvider.php ────────►────────┤
    ├── ShipProvider.php ◄──registered─in─◄─┘
    └── ...

    The following diagram illustrates the registration flow of service providers in the above folder structure:

    - + \ No newline at end of file diff --git a/docs/next/components/optional-components/tests/index.html b/docs/next/components/optional-components/tests/index.html index c4064dfe8..1e156c280 100644 --- a/docs/next/components/optional-components/tests/index.html +++ b/docs/next/components/optional-components/tests/index.html @@ -4,7 +4,7 @@ Tests | Apiato - + @@ -118,7 +118,7 @@ Within this class, you can define the logic and data generation process for your testing data.

    Once you have defined your testing data, you can run the following command in your terminal:

    php artisan apiato:seed-test

    This command triggers the seeding process specifically for testing data, populating your application with the generated data.

    - + \ No newline at end of file diff --git a/docs/next/components/optional-components/values/index.html b/docs/next/components/optional-components/values/index.html index e64e86ccb..fee530cbd 100644 --- a/docs/next/components/optional-components/values/index.html +++ b/docs/next/components/optional-components/values/index.html @@ -4,7 +4,7 @@ Values | Apiato - + @@ -15,7 +15,7 @@ Additionally, they do not possess functionality or modify any state; their sole purpose is to hold data.

    Value Objects are particularly well-suited for use with Laravel attributes casting, which allows us to cast a Value Object to a specific type, enabling seamless integration with Eloquent models and database operations.

    To generate new values you may use the apiato:generate:value interactive command:

    php artisan apiato:generate:value

    Rules

    • All container-specific Values MUST be placed in the app/Containers/{section}/{container}/Values directory.
    • All general Values MUST be placed in the app/Ship/Values directory.
    • All Values MUST extend the App\Ship\Parents\Values\Value class.
      • The parent extension SHOULD be aliased as ParentValue.

    Folder Structure

    app
    └── Containers
    └── Section
    └── Container
    └── Values
    ├── Output.php
    ├── Region.php
    └── ...

    Code Example

    class Location extends Value
    {
    public function __construct(
    public float $latitude,
    public float $longitude,
    ) {
    }
    }
    - + \ No newline at end of file diff --git a/docs/next/consulting/index.html b/docs/next/consulting/index.html index baa8e7894..11027100f 100644 --- a/docs/next/consulting/index.html +++ b/docs/next/consulting/index.html @@ -4,13 +4,13 @@ Consulting | Apiato - +
    - + \ No newline at end of file diff --git a/docs/next/framework-features/api-versioning/index.html b/docs/next/framework-features/api-versioning/index.html index b348ea9b2..f15f7f8fd 100644 --- a/docs/next/framework-features/api-versioning/index.html +++ b/docs/next/framework-features/api-versioning/index.html @@ -4,13 +4,13 @@ API Versioning | Apiato - +
    - + \ No newline at end of file diff --git a/docs/next/framework-features/code-generator/index.html b/docs/next/framework-features/code-generator/index.html index 327965acb..54e95ea5b 100644 --- a/docs/next/framework-features/code-generator/index.html +++ b/docs/next/framework-features/code-generator/index.html @@ -4,7 +4,7 @@ Code Generator | Apiato - + @@ -22,7 +22,7 @@ However, it is crucial to adhere to one essential rule:

    • The name of the file and the folder structure in app/Ship/Generators/CustomStubs MUST exactly match those in vendor/apiato/core/Generator/Stubs.

    To illustrate the process, let's assume you want to customize the creation of an action. Follow these steps:

    1. Locate the action.stub file in vendor/apiato/core/Generator/Stubs/actions.
    2. Copy the action.stub file and paste it into the app/Ship/Generators/CustomStubs/actions directory.
    3. Make the desired changes to the copied action.stub file according to your requirements.

    By completing these steps, whenever you run the php artisan apiato:generate:action command, your customized stub file will be employed instead of the default one, applying your modifications to the generated action files.

    - + \ No newline at end of file diff --git a/docs/next/framework-features/etag/index.html b/docs/next/framework-features/etag/index.html index e7fc8e01f..f54107afc 100644 --- a/docs/next/framework-features/etag/index.html +++ b/docs/next/framework-features/etag/index.html @@ -4,7 +4,7 @@ Etag | Apiato - + @@ -12,7 +12,7 @@
    Version: Next 🚧

    Etag

    The ETag or entity tag is part of HTTP, the protocol for the World Wide Web. It is one of several mechanisms that HTTP provides for Web cache validation, which allows a client to make conditional requests.

    You can read more about this feature in the Requests documentation.

    - + \ No newline at end of file diff --git a/docs/next/framework-features/index.html b/docs/next/framework-features/index.html index b19cca3d5..00ab2f31c 100644 --- a/docs/next/framework-features/index.html +++ b/docs/next/framework-features/index.html @@ -4,13 +4,13 @@ Framework Features | Apiato - + - + \ No newline at end of file diff --git a/docs/next/framework-features/profiler/index.html b/docs/next/framework-features/profiler/index.html index c41ff0b42..cc8194d21 100644 --- a/docs/next/framework-features/profiler/index.html +++ b/docs/next/framework-features/profiler/index.html @@ -4,7 +4,7 @@ Profiler | Apiato - + @@ -17,7 +17,7 @@ Apiato employs the Apiato\Core\Middlewares\Http\ProfilerMiddleware to include the profiling data in the response.

    The profiler feature is initially disabled by default. To enable it, you should edit the .env file and set DEBUGBAR_ENABLED=true.

    To customize and manage the profiler response, you'll need to make adjustments in the configuration file located at app/Ship/Configs/debugbar.php.

    The following is an example of the profiler response:

    {
    "_profiler": {
    "__meta": {
    "id": "X167f293230e3457f1bbd95d9c82aba4a",
    "datetime": "2017-09-22 18:45:27",
    "utime": 1506105927.799299,
    "method": "GET",
    "uri": "/",
    "ip": "172.20.0.1"
    },
    "messages": {
    "count": 0,
    "messages": []
    },
    "time": {
    "start": 1506105922.742068,
    "end": 1506105927.799333,
    "duration": 5.057265043258667,
    "duration_str": "5.06s",
    "measures": [
    {
    "label": "Booting",
    "start": 1506105922.742068,
    "relative_start": 0,
    "end": 1506105923.524004,
    "relative_end": 1506105923.524004,
    "duration": 0.7819359302520752,
    "duration_str": "781.94ms",
    "params": [],
    "collector": null
    },
    {
    "label": "Application",
    "start": 1506105923.535343,
    "relative_start": 0.7932748794555664,
    "end": 1506105927.799336,
    "relative_end": 0.00000286102294921875,
    "duration": 4.26399302482605,
    "duration_str": "4.26s",
    "params": [],
    "collector": null
    }
    ]
    },
    "memory": {
    "peak_usage": 13234248,
    "peak_usage_str": "12.62MB"
    },
    "exceptions": {
    "count": 0,
    "exceptions": []
    },
    "route": {
    "uri": "GET /",
    "middleware": "api, throttle:30,1",
    "domain": "http://api.apiato.test",
    "as": "apis_root_page",
    "controller": "App\\Containers\\Welcome\\UI\\API\\Controllers\\Controller@apiRoot",
    "namespace": "App\\Containers\\Welcome\\UI\\API\\Controllers",
    "prefix": "/",
    "where": [],
    "file": "app/Containers/Welcome/UI/API/Controllers/Controller.php:20-25"
    },
    "queries": {
    "nb_statements": 0,
    "nb_failed_statements": 0,
    "accumulated_duration": 0,
    "accumulated_duration_str": "0μs",
    "statements": []
    },
    "logs": {
    "count": 3,
    "messages": [
    {
    "message": "...",
    "message_html": null,
    "is_string": false,
    "label": "error",
    "time": 1506105927.694807
    },
    {
    "message": "...",
    "message_html": null,
    "is_string": false,
    "label": "error",
    "time": 1506105927.694811
    },
    {
    "message": "[2017-09-18 17:38:15] testing.INFO: New User registration. ID = 970ylqvaogmxnbdr | Email = apiato@mail.test. Thank you for signing up.\n</div>\n</body>\n</html>\n \n",
    "message_html": null,
    "is_string": false,
    "label": "info",
    "time": 1506105927.694812
    }
    ]
    },
    "auth": {
    "guards": {
    "web": "array:2 [\n \"name\" => \"Guest\"\n \"user\" => array:1 [\n \"guest\" => true\n ]\n]",
    "api": "array:2 [\n \"name\" => \"Guest\"\n \"user\" => array:1 [\n \"guest\" => true\n ]\n]"
    },
    "names": ""
    },
    "gate": {
    "count": 0,
    "messages": []
    }
    }
    }
    - + \ No newline at end of file diff --git a/docs/next/framework-features/rate-limiting/index.html b/docs/next/framework-features/rate-limiting/index.html index 35ee98df5..6239d7a7e 100644 --- a/docs/next/framework-features/rate-limiting/index.html +++ b/docs/next/framework-features/rate-limiting/index.html @@ -4,7 +4,7 @@ Rate Limiting | Apiato - + @@ -17,7 +17,7 @@ You can disable it on specific endpoints or globally.

    On a specific endpoint

    Rate limiting can be disabled by removing the api middleware from an endpoint using withoutMiddleware('throttle:api') method. Read More.

    Globally

    To disable rate limiting completely, set GLOBAL_API_RATE_LIMIT_ENABLED to false in the .env file.

    - + \ No newline at end of file diff --git a/docs/next/framework-features/rbac/index.html b/docs/next/framework-features/rbac/index.html index 05c94292a..e8a84e212 100644 --- a/docs/next/framework-features/rbac/index.html +++ b/docs/next/framework-features/rbac/index.html @@ -4,7 +4,7 @@ Role Based Access Control | Apiato - + @@ -12,7 +12,7 @@
    - + \ No newline at end of file diff --git a/docs/next/getting-started/best-practices/index.html b/docs/next/getting-started/best-practices/index.html index 3c7de51de..526bbc8c1 100644 --- a/docs/next/getting-started/best-practices/index.html +++ b/docs/next/getting-started/best-practices/index.html @@ -4,7 +4,7 @@ Best Practices | Apiato - + @@ -45,7 +45,7 @@ This gives maintainers of the API enough information to understand the problem that’s occurred. We don’t want errors to bring down our system, so we can leave them unhandled, which means that the API consumer has to handle them.

    Common error HTTP status codes include:

    • 200 OK Server successfully returned the requested data.
    • 201 CREATED Server successfully created or modified the requested resource.
    • 204 NO CONTENT Server successfully deleted the requested resource.
    • 400 INVALID REQUEST The request was invalid or cannot be served. The exact error should be explained in the error payload. E.g. „The JSON is not valid“.
    • 401 UNAUTHORIZED The request requires an user authentication.
    • 403 FORBIDDEN The server understood the request, but is refusing it or the access is not allowed.
    • 404 NOT FOUND There is no resource behind the URI.
    • 422 Unprocessable Entity Should be used if the server cannot process the enitity, e.g. if an image cannot be formatted or mandatory fields are missing in the payload.
    • 500 INTERNAL SERVER ERROR Internal Server Error.
    • 502 BAD GATEWAY Server received an invalid response from the upstream server while trying to fulfill the request.
    • 503 SERVICE UNAVAILABLE Service unavailable.

    Naming Conventions For Routes & Actions

    • ListResources: to fetch all resources.
    • FindResourceByID: to search for a single resource by its unique identifier.
    • CreateResource: to create a new resource.
    • UpdateResource: to update/edit existing resource.
    • DeleteResource: to delete a resource.
    - + \ No newline at end of file diff --git a/docs/next/getting-started/customized-laravel-components/index.html b/docs/next/getting-started/customized-laravel-components/index.html index 04330ec5a..ccc005877 100644 --- a/docs/next/getting-started/customized-laravel-components/index.html +++ b/docs/next/getting-started/customized-laravel-components/index.html @@ -4,14 +4,14 @@ Customized Laravel Components | Apiato - +
    Version: Next 🚧

    Customized Laravel Components

    Apiato provides a refined organization for Laravel default class locations. Here, you can find the default Laravel components and their corresponding locations within Apiato.

    Kernels

    • Http Kernel is moved from app/Http to app/Ship/Kernels and renamed to HttpKernel.

    • Console Kernel is moved from app/Console to app/Ship/Kernels and renamed to ConsoleKernel.

    Middlewares

    • Middlewares are moved from app/Http/Middleware to app/Ship/Middlewares.

    Handler

    • Exception Handler is moved from app/Exceptions to app/Ship/Exceptions/Handlers and renamed to ExceptionsHandler.

    Providers

    • For information about the new locations of Providers, please refer to this link.

    Routes

    Web and API

    Apiato introduces a new approach to route organization and does not use the default routes/web.php and routes/api.php files. Therefore, you won't find these files in Apiato. To learn more, please visit this link.

    Channels

    • The channels.php file has been relocated from routes to app/Ship/Broadcasts.

    Console

    • The console.php file has been moved from routes to app/Ship/Commands and renamed to closures.php.
    - + \ No newline at end of file diff --git a/docs/next/getting-started/installation/index.html b/docs/next/getting-started/installation/index.html index bb49a0faf..f03b215ba 100644 --- a/docs/next/getting-started/installation/index.html +++ b/docs/next/getting-started/installation/index.html @@ -4,18 +4,18 @@ Installation | Apiato - +
    Version: Next 🚧

    Installation

    Your First Apiato Project

    Before creating your first Apiato project, you should ensure that your local machine has PHP and Composer installed. -If you are developing on macOS, PHP and Composer can be installed via Homebrew.

    After you have installed PHP and Composer, you may create a new Apiato project via the Composer create-project command:

    composer create-project apiato/apiato example-app

    Development Environment Setup

    You can run Apiato in any environment that you can run Laravel.

    tip

    Visit Laravel Installation for more details.

    Initial Configuration

    All the configuration files for the Laravel framework are stored in the config folder +If you are developing on macOS, PHP and Composer can be installed via Homebrew.

    After you have installed PHP and Composer, you may create a new Apiato project via the Composer create-project command:

    composer create-project apiato/apiato example-app --no-scripts

    Development Environment Setup

    You can run Apiato in any environment that you can run Laravel.

    tip

    Visit Laravel Installation for more details.

    Initial Configuration

    All the configuration files for the Laravel framework are stored in the config folder and all the configuration files for the Apiato framework are stored in app/Ship/Configs. Each option is documented, so feel free to look through the files and get familiar with the options available to you.

    Apiato needs almost no additional configuration out of the box. You are free to get started developing! However, you may wish to review the app/Ship/Configs/apiato.php file and its documentation. -It contains several options that you may wish to change according to your application.

    Environment Based Configuration

    Since many of Apiato configuration option values may vary +It contains several options that you may wish to change, according to your application.

    Environment Based Configuration

    Since many of Apiato configuration option values may vary depending on whether your application is running on your local machine or on a production web server, many important configuration values are defined using the .env file that exists at the root of your application.

    Your .env file should not be committed to your application's source control, since each developer / server using your application could require a different environment configuration. @@ -41,8 +41,8 @@ However, you can change this behavior.

    For example, if you'd like to achieve urls like apiato.test/api/, follow these steps:

    1. Open your .env file and modify the API domain by updating the API_URL value from http://api.apiato.test to http://apiato.test to remove the subdomain.
    2. In the app/Ship/Configs/apiato.php configuration file:
      • Set the prefix to api/.
      • Set enable_version_prefix to false.

    Generating API Documentation

    Apiato includes a convenient Documentation Generator package that utilizes ApiDocJs for API documentation generation.

    To get started, install ApiDocJs using NPM or your preferred dependency manager:

    npm install

    Next, generate the API documentation by executing the following command:

    php artisan apiato:apidoc

    Let's Play

    To witness Apiato in action, assuming you are using the default Subdomain and API Version Prefix configuration, you should be able to access the following URLs and see the following results:

    Web (Browser)

    API (HTTP Client)

    Next Steps

    Now that you have created your Apiato project, you may be wondering what to learn next. -If you're looking for a place to start, you should check out the following resources:

    - +If you're looking for a place to start, you should check out the following resources:

    + \ No newline at end of file diff --git a/docs/next/pacakges/documentation/index.html b/docs/next/pacakges/documentation/index.html index f6a67f49f..f09d9b33f 100644 --- a/docs/next/pacakges/documentation/index.html +++ b/docs/next/pacakges/documentation/index.html @@ -4,7 +4,7 @@ Documentation | Apiato - + @@ -15,7 +15,7 @@ access-private-docs-permission values in documentation config. By default, users need access-private-docs permission to access private docs.

    Edit Default Generated Values in Templates

    Apiato by defaults generates 2 API documentations, each one has its own apidoc.json file. Both can be modified from the Documentation Container in app/Containers/Vendor/Documentation/ApiDocJs and need Source code modification.

    Edit the Documentation Header

    The header is usually the Overview of your API. It contains Info about authenticating users, making requests, responses, potential errors, rate limiting, pagination, query parameters and anything you want.

    All this information is written in app/Containers/Vendor/Documentation/ApiDocJs/shared/header.template.en.md file, and the same file is used as header for both private and public documentations.

    To edit its content you need to modify its source code and open the markdown file in any markdown editor and edit it.

    You will notice some variables like {{rate-limit}} and {{token-expires}}. Those are replaced when running apiato:apidoc with real values from your application configuration files.

    Feel free to extend them to include more info about your API from the app/Containers/Vendor/Documentation/Tasks/RenderTemplatesTask.php class.

    Localization for Documentation Header

    Default, the documentation title is in English en localization.

    See which locales are supported by going in app/Containers/Vendor/Documentation/ApiDocJs/shared

    There will be some header.template.{locale}.md files in the folder.

    You can change the language by adding APIDOC_LOCALE=ru to the .env file.

    If you didn't find a file with your locale, you can create it. You need to modify its source code and create new file like header.template.cn.md

    - + \ No newline at end of file diff --git a/docs/next/pacakges/index.html b/docs/next/pacakges/index.html index d6cd4a20d..4e19f65dd 100644 --- a/docs/next/pacakges/index.html +++ b/docs/next/pacakges/index.html @@ -4,7 +4,7 @@ Overview | Apiato - + @@ -21,7 +21,7 @@ that allows installing/updating containers.
  • You must provide the key extra.apiato.container.name. This key indicates the name of the folder (e.g., container) when installing the package to the app/Containers/Vendor directory. In the shown example, the container would be installed to app/Containers/Vendor/Foo.
  • - + \ No newline at end of file diff --git a/docs/next/pacakges/localization/index.html b/docs/next/pacakges/localization/index.html index 7689ebdd0..0b2483034 100644 --- a/docs/next/pacakges/localization/index.html +++ b/docs/next/pacakges/localization/index.html @@ -4,7 +4,7 @@ Localization | Apiato - + @@ -41,7 +41,7 @@ language in this specific language (e.g., locale_name => Deutsch). Furthermore, the language name is outputted in the applications default name (e.g., configured in app.locale). This would result in default_name => German.

    The same applies to the regions that are defined (e.g., de-DE). Consequently, this results in locale_name => Deutschland and default_name = Germany.

    Tests

    To change the default language in your tests requests. You can set the env language in the phpunit.xml file.

    - + \ No newline at end of file diff --git a/docs/next/pacakges/social-authentication/index.html b/docs/next/pacakges/social-authentication/index.html index f0ae3b33a..435830271 100644 --- a/docs/next/pacakges/social-authentication/index.html +++ b/docs/next/pacakges/social-authentication/index.html @@ -4,7 +4,7 @@ Social Authentication | Apiato - + @@ -19,7 +19,7 @@ to get the oauth info and user data respectively.

    Social Authentication Container Customization

    You can customize this container by publishing its config and modifying its values

    php artisan vendor:publish

    Config file will be copied to app/Ship/Configs/vendor-socialAuth.php

    Support new Auth Provider

    1. Publish the configs
    2. Create your new auth provider by implementing the App\Containers\Vendor\SocialAuth\Contracts\SocialAuthProvider contract.
      To get an idea about how to implement your own provider you can check out supported providers here app/Containers/Vendor/SocialAuth/SocialAuthProviders.
    3. Add your new provider to providers array in the vendor-socialAuth config.
        'providers' => [
    ...
    'something' => Location\Of\Your\Provider\SomthingSocialAuthProvider::class,
    ],

    Changing default used Repository, Transformer & DB user table name

    This container depends on Apiato default user repository, transformer & database user table name. If you changed those defaults you can update and provide them in the configs.

    - + \ No newline at end of file diff --git a/docs/next/prologue/contribution-guide/index.html b/docs/next/prologue/contribution-guide/index.html index 85e89b997..8ba2db093 100644 --- a/docs/next/prologue/contribution-guide/index.html +++ b/docs/next/prologue/contribution-guide/index.html @@ -4,7 +4,7 @@ Contribution Guide | Apiato - + @@ -37,7 +37,7 @@ after pull requests are merged. This allows us to focus on the content of the contribution and not the code style.

    Code of Conduct

    The Apiato code of conduct is derived from the Ruby code of conduct. Any violations of the code of conduct may be reported to Mohammad Alavi (mohammad.alavi1990@gmail.com):

    • Participants will be tolerant of opposing views.
    • Participants must ensure that their language and actions are free of personal attacks and disparaging personal remarks.
    • When interpreting the words and actions of others, participants should always assume good intentions.
    • Behavior that can be reasonably considered harassment will not be tolerated.
    - + \ No newline at end of file diff --git a/docs/next/prologue/release-notes/index.html b/docs/next/prologue/release-notes/index.html index b031fbf3e..56156f3d4 100644 --- a/docs/next/prologue/release-notes/index.html +++ b/docs/next/prologue/release-notes/index.html @@ -4,7 +4,7 @@ Release Notes | Apiato - + @@ -17,7 +17,7 @@ since major releases of Apiato do include breaking changes. However, we strive to always ensure you may update to a new major release in one day or less.

    Support Policy

    For all Apiato releases, bug fixes are provided for 18 months and security fixes are provided for 2 years.

    VersionPHP (*)ReleaseBug Fixes UntilSecurity Fixes Until
    107.3 - 8.1April 25th, 2021October 25th, 2022April 25th, 2023
    118.0 - 8.2April 27th, 2022October 27th, 2023April 27th, 2024
    128.1 - 8.2June 4th, 2023December 4th, 2024June 4th, 2025
    138.2Q1 2024August 5th, 2025February 3rd, 2026

    (*) Supported PHP versions

    Apiato 12

    Full Changelog: https://github.com/apiato/apiato/compare/v11.3.2...v12.0.0

    PHP 8.1

    Apiato 12.x requires a minimum PHP version of 8.1.

    Breaking Changes

    • Upgraded to Laravel v10 (All Laravel files (e.g. configs, .env, etc...) are now synced with the latest Laravel changes)
    • Updated Composer dependencies to their latest version
    • Laravel Passport route registration & customization has changed. Passport routes are now reside in a dedicated route file (Instead of registering them in the provider).
    • Middleware $routeMiddleware field is renamed to $middlewareAliases
    • Trimmed down the TestCase by removing some useless traits including:
    TestsMockHelperTrait
    TestsResponseHelperTrait
    • encode() method return value has changed -> In case of unencodable value (e.g. null), now returns null instead of ''
    • decode() method return value has changed -> In case of undecodable value (e.g. null), now returns null instead of []
    • StateKeeperTrait is removed from Request

    None Breaking Changes

    • Everything is refactored to use constructor injection instead of directly using the Service Container like so app(CreateUserByCredentialsTask::class)->run()
    • Added more tests and refactored the rest
    • Switched to invokable controllers
    \\ from
    Route::get('profile', [GetAuthenticatedUserController::class, 'getAuthenticatedUser']);
    \\ to
    Route::get('profile', GetAuthenticatedUserController::class);
    • All rotues are moved into the private documentation. e.g. RefreshProxyForWebClient.v1.public.php -> RefreshProxyForWebClient.v1.private.php
    • Added some getter methods to the Request including:
    withUrlParameters()
    getAccessArray()
    getDecodeArray()
    getUrlParametersArray()
    • Added a TestAssertionHelperTrait to the TestCase which provides some usefull assertions

    Bug Fixes

    • withMeta() method on ResponseTrait now correctly includes added meta data
    • Calling invokable controllers from routes #174
    • Exception when try to generate an WEB CRUD Controller from generator #171
    • PHP 8.1 warning on passing null to explode #176
    - + \ No newline at end of file diff --git a/docs/next/prologue/upgrade-guide/index.html b/docs/next/prologue/upgrade-guide/index.html index d85515f7f..d33d4943c 100644 --- a/docs/next/prologue/upgrade-guide/index.html +++ b/docs/next/prologue/upgrade-guide/index.html @@ -4,13 +4,13 @@ Upgrade Guide | Apiato - +
    Version: Next 🚧

    Upgrade Guide

    Upgrade from 11.0 to 12.0

    WORK IN PROGRESS

    - + \ No newline at end of file diff --git a/docs/next/security/authentication/index.html b/docs/next/security/authentication/index.html index 15d1604e8..ae3feabb0 100644 --- a/docs/next/security/authentication/index.html +++ b/docs/next/security/authentication/index.html @@ -4,7 +4,7 @@ Authentication | Apiato - + @@ -67,7 +67,7 @@ you can navigate to the app/Ship/Providers/RouteServiceProvider.php file and update the LOGIN constant.

    Passing The Access Token

    When calling routes that are protected by Passport, your application's API consumers should specify their access token as a Bearer token in the Authorization header of their request. For example, when using the Guzzle HTTP library:

    use Illuminate\Support\Facades\Http;

    $response = Http::withHeaders([
    'Accept' => 'application/json',
    'Authorization' => 'Bearer '.$accessToken,
    ])->get('http://api.apiato.test/v1/users');

    return $response->json();

    Configuration

    Most of the configuration is done in the app/Ships/Configs/apiato.php file.

    Social Authentication

    For Social Authentication visit the Social Authentication page.

    - + \ No newline at end of file diff --git a/docs/next/security/authorization/index.html b/docs/next/security/authorization/index.html index 177517834..9b81c87d4 100644 --- a/docs/next/security/authorization/index.html +++ b/docs/next/security/authorization/index.html @@ -4,7 +4,7 @@ Authorization | Apiato - + @@ -19,7 +19,7 @@ you ensure that unauthorized users are denied access before any further processing takes place.

    Default Roles & Permissions

    Apiato comes with some default Roles and Permissions. You can find them in app/Containers/AppSection/Authorization/Data/Seeders. You can use them as a starting point, or delete them and create your own.

    Code Example

    Protecting the delete user endpoint with delete-users permission:

    use App\Ship\Parents\Requests\Request as ParentRequest;

    class DeleteUserRequest extends ParentRequest
    {
    protected array $access = [
    'permissions' => 'delete-users',
    'roles' => '',
    ];

    public function authorize(): bool
    {
    return $this->check([
    'hasAccess',
    ]);
    }
    }

    Authorization failed JSON response:

    {
    "message": "This action is unauthorized.",
    "errors": []
    }
    - + \ No newline at end of file diff --git a/docs/next/security/email-varification/index.html b/docs/next/security/email-varification/index.html index a84077353..5bd4811b1 100644 --- a/docs/next/security/email-varification/index.html +++ b/docs/next/security/email-varification/index.html @@ -4,7 +4,7 @@ Email Verification | Apiato - + @@ -22,7 +22,7 @@ when using a load balancer, set the protected $proxies = '*' in the app/Ship/Middlewares/TrustProxies.php or customize it according to your needs.

    - + \ No newline at end of file diff --git a/docs/next/security/hash-id/index.html b/docs/next/security/hash-id/index.html index ebe8c78bb..d0a38fb35 100644 --- a/docs/next/security/hash-id/index.html +++ b/docs/next/security/hash-id/index.html @@ -4,7 +4,7 @@ Hash ID | Apiato - + @@ -20,7 +20,7 @@ You can set the HASH_ID_KEY in the .env file to any random string. Apiato defaults to the APP_KEY should this not be set.

    danger

    The HASH_ID_KEY acts as the salt during hashing of the ID. This should never be changed in production as it renders all previously generated IDs impossible to decode.

    Route Model Binding

    Laravel Route Model Binding feature is supported out of the box and Apiato will automatically decode the ID for you.

    - + \ No newline at end of file diff --git a/docs/next/security/password-reset/index.html b/docs/next/security/password-reset/index.html index 23788b6c8..4260cddc6 100644 --- a/docs/next/security/password-reset/index.html +++ b/docs/next/security/password-reset/index.html @@ -4,7 +4,7 @@ Password Reset | Apiato - + @@ -15,7 +15,7 @@ in the allowed-reset-password-urls array within the appSection-authentication configuration.

    Routing

    To request a password reset link, call the /password/forgot endpoint with the user's email address.

    Resetting The Password

    To reset the user's password, call the /password/reset endpoint with the user's email address, new password, and password reset token.

    Process Flow

    1. Add your web app's password reset page URL, for example, https://myapp.com/password/reset, to the allowed-reset-password-urls array within the appSection-authentication configuration.

    2. Call the /password/forgot endpoint with a reset URL of your choice, which should correspond to one of the URLs in the allowed-reset-password-urls array. This endpoint will send the user an email containing a link like this:
      https://myapp.com/password/resetd?email=mohammad.alavi1990@gmail.com&token=51f8d80182f3785648c9b9dc7162719d158fc418b3cca86c14963638ec83d663

    3. When the user clicks on that link, they will be directed to your front-end app's password reset page. From there, you can collect the user's new password and make a call to the /password/reset endpoint with all the required fields to complete the password reset.

    - + \ No newline at end of file diff --git a/docs/next/security/registration/index.html b/docs/next/security/registration/index.html index d79d2134a..674aa99a9 100644 --- a/docs/next/security/registration/index.html +++ b/docs/next/security/registration/index.html @@ -4,13 +4,13 @@ Registration | Apiato - +
    Version: Next 🚧

    Registration

    Apiato supports two default user registration methods:

    1. Register by Credentials
    2. Register by Social Account

    You can also extend these methods or add new ones to customize your registration process.

    Register by Credentials

    To register a new user, send a POST request to the /register endpoint.

    api.apiato.test/v1/register
    tip

    Don't forget to add Accept: application/json header to your request.

    The /register endpoint expects a string email address and a string password field.

    {
    "email": "gandalg@the.grey",
    "password": "password"
    }

    You should receive a response similar to the following:

    {
    "data": {
    "object": "User",
    "id": "XbPW7awNkzl83LD6",
    "name": null,
    "email": "john@doe.com",
    "email_verified_at": null,
    "gender": null,
    "birth": null
    },
    "meta": {
    "include": [
    "roles",
    "permissions"
    ],
    "custom": []
    }
    }

    Register by Social Account

    (Facebook, Twitter, Google, etc...)

    Checkout the Social Authentication documentation.

    - + \ No newline at end of file diff --git a/docs/next/tags/action/index.html b/docs/next/tags/action/index.html index a4e0b0dec..e00029c9b 100644 --- a/docs/next/tags/action/index.html +++ b/docs/next/tags/action/index.html @@ -4,13 +4,13 @@ 9 docs tagged with "action" | Apiato - +

    9 docs tagged with "action"

    View All Tags

    Actions

    Actions serve as the embodiment of the application's Use Cases,

    Commands

    Apiato commands are just Laravel Commands,

    Controllers

    Controllers are tasked with two primary responsibilities:

    Criterias

    To prevent overlap with the L5 Repository documentation, this page

    Events

    Apiato events are just Laravel Events,

    Repositories

    Apiato provides a powerful repository pattern implementation based on the L5 Repository package.

    Requests

    Requests components are a way to interact with the current HTTP request

    Sub Actions

    SubActions are designed to eliminate code duplication within Actions.

    Tasks

    Tasks are specialized classes that hold shared business logic,

    - + \ No newline at end of file diff --git a/docs/next/tags/api-versioning/index.html b/docs/next/tags/api-versioning/index.html index 8bb1c924d..1409352da 100644 --- a/docs/next/tags/api-versioning/index.html +++ b/docs/next/tags/api-versioning/index.html @@ -4,13 +4,13 @@ One doc tagged with "api-versioning" | Apiato - +

    One doc tagged with "api-versioning"

    View All Tags

    API Versioning

    Apiato provides a streamlined approach to implementing API versioning within your application.

    - + \ No newline at end of file diff --git a/docs/next/tags/architecture/index.html b/docs/next/tags/architecture/index.html index fb17c8d56..05022df5e 100644 --- a/docs/next/tags/architecture/index.html +++ b/docs/next/tags/architecture/index.html @@ -4,13 +4,13 @@ 5 docs tagged with "architecture" | Apiato - +

    5 docs tagged with "architecture"

    View All Tags

    Container

    Containers are at the core of Apiato.

    Porto

    Porto is a modern software architectural pattern that offers developers a comprehensive set of guidelines,

    Request Lifecycle

    When using any tool in the "real world", you feel more confident if you understand how that tool works.

    - + \ No newline at end of file diff --git a/docs/next/tags/authorization/index.html b/docs/next/tags/authorization/index.html index d8abb54da..e9995306f 100644 --- a/docs/next/tags/authorization/index.html +++ b/docs/next/tags/authorization/index.html @@ -4,13 +4,13 @@ 2 docs tagged with "authorization" | Apiato - +

    2 docs tagged with "authorization"

    View All Tags

    Authorization

    Apiato provides a Role-Based Access Control (RBAC) through its Authorization Container.

    Policies

    Apiato policies are just Laravel Policies,

    - + \ No newline at end of file diff --git a/docs/next/tags/code-generator/index.html b/docs/next/tags/code-generator/index.html index 02ed55de0..67cffcb92 100644 --- a/docs/next/tags/code-generator/index.html +++ b/docs/next/tags/code-generator/index.html @@ -4,13 +4,13 @@ One doc tagged with "code-generator" | Apiato - +

    One doc tagged with "code-generator"

    View All Tags

    Code Generator

    Apiato comes with a powerful code generator that can help you to generate all the boilerplate code for your containers.

    - + \ No newline at end of file diff --git a/docs/next/tags/command/index.html b/docs/next/tags/command/index.html index c5d4f0f92..e4a928342 100644 --- a/docs/next/tags/command/index.html +++ b/docs/next/tags/command/index.html @@ -4,13 +4,13 @@ One doc tagged with "command" | Apiato - +

    One doc tagged with "command"

    View All Tags

    Commands

    Apiato commands are just Laravel Commands,

    - + \ No newline at end of file diff --git a/docs/next/tags/component/index.html b/docs/next/tags/component/index.html index fee5b1907..a54ca0580 100644 --- a/docs/next/tags/component/index.html +++ b/docs/next/tags/component/index.html @@ -4,13 +4,13 @@ 29 docs tagged with "component" | Apiato - +

    29 docs tagged with "component"

    View All Tags

    Actions

    Actions serve as the embodiment of the application's Use Cases,

    Authorization

    Apiato provides a Role-Based Access Control (RBAC) through its Authorization Container.

    Commands

    Apiato commands are just Laravel Commands,

    Configs

    Apiato configs are just Laravel configs, and they function in the exact same way as Laravel configs.

    Controllers

    Controllers are tasked with two primary responsibilities:

    Criterias

    To prevent overlap with the L5 Repository documentation, this page

    Events

    Apiato events are just Laravel Events,

    Exceptions

    Exceptions are used to handle errors and exceptions in the application.

    Factories

    Apiato factories are just Laravel Factories,

    Helpers

    You have the option to create your own global "helper" PHP functions in designated directories, and Apiato will automatically autoload them for you.

    Jobs

    Apiato jobs are just Laravel Jobs,

    Mail

    Apiato mails are just Laravel Mails,

    Middlewares

    Apiato middlewares are just Laravel Middlewares,

    Migrations

    Apiato migrations are just Laravel Migrations,

    Models

    Models are responsible for representing the data of the application

    Notifications

    Apiato notifications are just Laravel Notifications,

    Policies

    Apiato policies are just Laravel Policies,

    Repositories

    Apiato provides a powerful repository pattern implementation based on the L5 Repository package.

    Requests

    Requests components are a way to interact with the current HTTP request

    Routes

    Routes are responsible for mapping incoming HTTP requests to their corresponding controller functions.

    Seeders

    Apiato seeders are just Laravel Seeders,

    Sub Actions

    SubActions are designed to eliminate code duplication within Actions.

    Tasks

    Tasks are specialized classes that hold shared business logic,

    Tests

    Apiato is built with testing in mind.

    Values

    Value Objects are short names for known "Value Objects",

    Views

    Views offer a convenient mechanism for organizing HTML content in separate files.

    - + \ No newline at end of file diff --git a/docs/next/tags/config/index.html b/docs/next/tags/config/index.html index b3f9fab3a..af53b20fa 100644 --- a/docs/next/tags/config/index.html +++ b/docs/next/tags/config/index.html @@ -4,13 +4,13 @@ One doc tagged with "config" | Apiato - +

    One doc tagged with "config"

    View All Tags

    Configs

    Apiato configs are just Laravel configs, and they function in the exact same way as Laravel configs.

    - + \ No newline at end of file diff --git a/docs/next/tags/container/index.html b/docs/next/tags/container/index.html index 981121bec..94040b6fb 100644 --- a/docs/next/tags/container/index.html +++ b/docs/next/tags/container/index.html @@ -4,13 +4,13 @@ One doc tagged with "container" | Apiato - +

    One doc tagged with "container"

    View All Tags

    Container

    Containers are at the core of Apiato.

    - + \ No newline at end of file diff --git a/docs/next/tags/controller/index.html b/docs/next/tags/controller/index.html index e9ca346bb..6b65769ec 100644 --- a/docs/next/tags/controller/index.html +++ b/docs/next/tags/controller/index.html @@ -4,13 +4,13 @@ 8 docs tagged with "controller" | Apiato - +

    8 docs tagged with "controller"

    View All Tags

    Actions

    Actions serve as the embodiment of the application's Use Cases,

    Controllers

    Controllers are tasked with two primary responsibilities:

    Middlewares

    Apiato middlewares are just Laravel Middlewares,

    Requests

    Requests components are a way to interact with the current HTTP request

    Routes

    Routes are responsible for mapping incoming HTTP requests to their corresponding controller functions.

    Sub Actions

    SubActions are designed to eliminate code duplication within Actions.

    Views

    Views offer a convenient mechanism for organizing HTML content in separate files.

    - + \ No newline at end of file diff --git a/docs/next/tags/criteria/index.html b/docs/next/tags/criteria/index.html index 823320ff7..20044f210 100644 --- a/docs/next/tags/criteria/index.html +++ b/docs/next/tags/criteria/index.html @@ -4,13 +4,13 @@ 2 docs tagged with "criteria" | Apiato - +

    2 docs tagged with "criteria"

    View All Tags

    Criterias

    To prevent overlap with the L5 Repository documentation, this page

    Repositories

    Apiato provides a powerful repository pattern implementation based on the L5 Repository package.

    - + \ No newline at end of file diff --git a/docs/next/tags/etag/index.html b/docs/next/tags/etag/index.html index 66ee87efe..9cbb335e0 100644 --- a/docs/next/tags/etag/index.html +++ b/docs/next/tags/etag/index.html @@ -4,13 +4,13 @@ One doc tagged with "etag" | Apiato - +

    One doc tagged with "etag"

    View All Tags

    Etag

    The ETag or entity tag is part of HTTP, the protocol for the World Wide Web.

    - + \ No newline at end of file diff --git a/docs/next/tags/event/index.html b/docs/next/tags/event/index.html index c27c1a06b..ea3defa51 100644 --- a/docs/next/tags/event/index.html +++ b/docs/next/tags/event/index.html @@ -4,13 +4,13 @@ 2 docs tagged with "event" | Apiato - +

    2 docs tagged with "event"

    View All Tags

    Events

    Apiato events are just Laravel Events,

    - + \ No newline at end of file diff --git a/docs/next/tags/exception/index.html b/docs/next/tags/exception/index.html index 458fe53a4..13732200f 100644 --- a/docs/next/tags/exception/index.html +++ b/docs/next/tags/exception/index.html @@ -4,13 +4,13 @@ One doc tagged with "exception" | Apiato - +

    One doc tagged with "exception"

    View All Tags

    Exceptions

    Exceptions are used to handle errors and exceptions in the application.

    - + \ No newline at end of file diff --git a/docs/next/tags/factory/index.html b/docs/next/tags/factory/index.html index c5f9b5c36..68b834f67 100644 --- a/docs/next/tags/factory/index.html +++ b/docs/next/tags/factory/index.html @@ -4,13 +4,13 @@ One doc tagged with "factory" | Apiato - +

    One doc tagged with "factory"

    View All Tags

    Factories

    Apiato factories are just Laravel Factories,

    - + \ No newline at end of file diff --git a/docs/next/tags/framework-feature/index.html b/docs/next/tags/framework-feature/index.html index b72552933..cccbc0da5 100644 --- a/docs/next/tags/framework-feature/index.html +++ b/docs/next/tags/framework-feature/index.html @@ -4,13 +4,13 @@ 6 docs tagged with "framework-feature" | Apiato - +

    6 docs tagged with "framework-feature"

    View All Tags

    API Versioning

    Apiato provides a streamlined approach to implementing API versioning within your application.

    Code Generator

    Apiato comes with a powerful code generator that can help you to generate all the boilerplate code for your containers.

    Etag

    The ETag or entity tag is part of HTTP, the protocol for the World Wide Web.

    Profiler

    Profiling is a crucial aspect of optimizing your application's performance

    - + \ No newline at end of file diff --git a/docs/next/tags/helper/index.html b/docs/next/tags/helper/index.html index b8e4495c6..9e8f4971b 100644 --- a/docs/next/tags/helper/index.html +++ b/docs/next/tags/helper/index.html @@ -4,13 +4,13 @@ One doc tagged with "helper" | Apiato - +

    One doc tagged with "helper"

    View All Tags

    Helpers

    You have the option to create your own global "helper" PHP functions in designated directories, and Apiato will automatically autoload them for you.

    - + \ No newline at end of file diff --git a/docs/next/tags/index.html b/docs/next/tags/index.html index b871bf518..b1a667263 100644 --- a/docs/next/tags/index.html +++ b/docs/next/tags/index.html @@ -4,13 +4,13 @@ Tags | Apiato - + - + \ No newline at end of file diff --git a/docs/next/tags/job/index.html b/docs/next/tags/job/index.html index 626a9d1af..4ce8e5116 100644 --- a/docs/next/tags/job/index.html +++ b/docs/next/tags/job/index.html @@ -4,13 +4,13 @@ One doc tagged with "job" | Apiato - +

    One doc tagged with "job"

    View All Tags

    Jobs

    Apiato jobs are just Laravel Jobs,

    - + \ No newline at end of file diff --git a/docs/next/tags/lifecycle/index.html b/docs/next/tags/lifecycle/index.html index ef22d2df0..529af6bb6 100644 --- a/docs/next/tags/lifecycle/index.html +++ b/docs/next/tags/lifecycle/index.html @@ -4,13 +4,13 @@ One doc tagged with "lifecycle" | Apiato - +

    One doc tagged with "lifecycle"

    View All Tags

    Request Lifecycle

    When using any tool in the "real world", you feel more confident if you understand how that tool works.

    - + \ No newline at end of file diff --git a/docs/next/tags/listener/index.html b/docs/next/tags/listener/index.html index a8a01033e..d233b3caa 100644 --- a/docs/next/tags/listener/index.html +++ b/docs/next/tags/listener/index.html @@ -4,13 +4,13 @@ One doc tagged with "listener" | Apiato - +

    One doc tagged with "listener"

    View All Tags

    Events

    Apiato events are just Laravel Events,

    - + \ No newline at end of file diff --git a/docs/next/tags/mail/index.html b/docs/next/tags/mail/index.html index 9524d1078..3bff2e0fd 100644 --- a/docs/next/tags/mail/index.html +++ b/docs/next/tags/mail/index.html @@ -4,13 +4,13 @@ One doc tagged with "mail" | Apiato - +

    One doc tagged with "mail"

    View All Tags

    Mail

    Apiato mails are just Laravel Mails,

    - + \ No newline at end of file diff --git a/docs/next/tags/main-component/index.html b/docs/next/tags/main-component/index.html index 05bbb9c70..30e3ab1cc 100644 --- a/docs/next/tags/main-component/index.html +++ b/docs/next/tags/main-component/index.html @@ -4,13 +4,13 @@ 10 docs tagged with "main-component" | Apiato - +

    10 docs tagged with "main-component"

    View All Tags

    Actions

    Actions serve as the embodiment of the application's Use Cases,

    Controllers

    Controllers are tasked with two primary responsibilities:

    Exceptions

    Exceptions are used to handle errors and exceptions in the application.

    Models

    Models are responsible for representing the data of the application

    Requests

    Requests components are a way to interact with the current HTTP request

    Routes

    Routes are responsible for mapping incoming HTTP requests to their corresponding controller functions.

    Sub Actions

    SubActions are designed to eliminate code duplication within Actions.

    Tasks

    Tasks are specialized classes that hold shared business logic,

    Views

    Views offer a convenient mechanism for organizing HTML content in separate files.

    - + \ No newline at end of file diff --git a/docs/next/tags/middleware/index.html b/docs/next/tags/middleware/index.html index 2336c1447..2f8bfeda9 100644 --- a/docs/next/tags/middleware/index.html +++ b/docs/next/tags/middleware/index.html @@ -4,13 +4,13 @@ 2 docs tagged with "middleware" | Apiato - +

    2 docs tagged with "middleware"

    View All Tags

    Middlewares

    Apiato middlewares are just Laravel Middlewares,

    - + \ No newline at end of file diff --git a/docs/next/tags/migration/index.html b/docs/next/tags/migration/index.html index 048f59124..0f9fedbb4 100644 --- a/docs/next/tags/migration/index.html +++ b/docs/next/tags/migration/index.html @@ -4,13 +4,13 @@ 2 docs tagged with "migration" | Apiato - +

    2 docs tagged with "migration"

    View All Tags

    Migrations

    Apiato migrations are just Laravel Migrations,

    Seeders

    Apiato seeders are just Laravel Seeders,

    - + \ No newline at end of file diff --git a/docs/next/tags/model/index.html b/docs/next/tags/model/index.html index 4c77790f8..afece1941 100644 --- a/docs/next/tags/model/index.html +++ b/docs/next/tags/model/index.html @@ -4,13 +4,13 @@ 4 docs tagged with "model" | Apiato - +

    4 docs tagged with "model"

    View All Tags

    Factories

    Apiato factories are just Laravel Factories,

    Models

    Models are responsible for representing the data of the application

    Values

    Value Objects are short names for known "Value Objects",

    - + \ No newline at end of file diff --git a/docs/next/tags/notification/index.html b/docs/next/tags/notification/index.html index 09ca0130c..99b594a5a 100644 --- a/docs/next/tags/notification/index.html +++ b/docs/next/tags/notification/index.html @@ -4,13 +4,13 @@ One doc tagged with "notification" | Apiato - +

    One doc tagged with "notification"

    View All Tags

    Notifications

    Apiato notifications are just Laravel Notifications,

    - + \ No newline at end of file diff --git a/docs/next/tags/optional-component/index.html b/docs/next/tags/optional-component/index.html index eac5ecbc1..4c4a3b354 100644 --- a/docs/next/tags/optional-component/index.html +++ b/docs/next/tags/optional-component/index.html @@ -4,13 +4,13 @@ 18 docs tagged with "optional-component" | Apiato - +

    18 docs tagged with "optional-component"

    View All Tags

    Authorization

    Apiato provides a Role-Based Access Control (RBAC) through its Authorization Container.

    Commands

    Apiato commands are just Laravel Commands,

    Configs

    Apiato configs are just Laravel configs, and they function in the exact same way as Laravel configs.

    Criterias

    To prevent overlap with the L5 Repository documentation, this page

    Events

    Apiato events are just Laravel Events,

    Factories

    Apiato factories are just Laravel Factories,

    Helpers

    You have the option to create your own global "helper" PHP functions in designated directories, and Apiato will automatically autoload them for you.

    Jobs

    Apiato jobs are just Laravel Jobs,

    Mail

    Apiato mails are just Laravel Mails,

    Middlewares

    Apiato middlewares are just Laravel Middlewares,

    Migrations

    Apiato migrations are just Laravel Migrations,

    Notifications

    Apiato notifications are just Laravel Notifications,

    Policies

    Apiato policies are just Laravel Policies,

    Repositories

    Apiato provides a powerful repository pattern implementation based on the L5 Repository package.

    Seeders

    Apiato seeders are just Laravel Seeders,

    Tests

    Apiato is built with testing in mind.

    Values

    Value Objects are short names for known "Value Objects",

    - + \ No newline at end of file diff --git a/docs/next/tags/policy/index.html b/docs/next/tags/policy/index.html index 88eb51d4e..3143370c0 100644 --- a/docs/next/tags/policy/index.html +++ b/docs/next/tags/policy/index.html @@ -4,13 +4,13 @@ 2 docs tagged with "policy" | Apiato - +

    2 docs tagged with "policy"

    View All Tags

    Authorization

    Apiato provides a Role-Based Access Control (RBAC) through its Authorization Container.

    Policies

    Apiato policies are just Laravel Policies,

    - + \ No newline at end of file diff --git a/docs/next/tags/porto/index.html b/docs/next/tags/porto/index.html index aab13e60d..9052becbc 100644 --- a/docs/next/tags/porto/index.html +++ b/docs/next/tags/porto/index.html @@ -4,13 +4,13 @@ 5 docs tagged with "porto" | Apiato - +

    5 docs tagged with "porto"

    View All Tags

    Container

    Containers are at the core of Apiato.

    Porto

    Porto is a modern software architectural pattern that offers developers a comprehensive set of guidelines,

    Request Lifecycle

    When using any tool in the "real world", you feel more confident if you understand how that tool works.

    - + \ No newline at end of file diff --git a/docs/next/tags/profiler/index.html b/docs/next/tags/profiler/index.html index f8b5abe4a..528135623 100644 --- a/docs/next/tags/profiler/index.html +++ b/docs/next/tags/profiler/index.html @@ -4,13 +4,13 @@ One doc tagged with "profiler" | Apiato - +

    One doc tagged with "profiler"

    View All Tags

    Profiler

    Profiling is a crucial aspect of optimizing your application's performance

    - + \ No newline at end of file diff --git a/docs/next/tags/queue/index.html b/docs/next/tags/queue/index.html index 5675cbd99..be2ca38b5 100644 --- a/docs/next/tags/queue/index.html +++ b/docs/next/tags/queue/index.html @@ -4,13 +4,13 @@ 3 docs tagged with "queue" | Apiato - +

    3 docs tagged with "queue"

    View All Tags

    Jobs

    Apiato jobs are just Laravel Jobs,

    Mail

    Apiato mails are just Laravel Mails,

    Notifications

    Apiato notifications are just Laravel Notifications,

    - + \ No newline at end of file diff --git a/docs/next/tags/rate-limiting/index.html b/docs/next/tags/rate-limiting/index.html index eb0ceeb55..d8cf011bf 100644 --- a/docs/next/tags/rate-limiting/index.html +++ b/docs/next/tags/rate-limiting/index.html @@ -4,13 +4,13 @@ One doc tagged with "rate-limiting" | Apiato - +

    One doc tagged with "rate-limiting"

    View All Tags
    - + \ No newline at end of file diff --git a/docs/next/tags/repository/index.html b/docs/next/tags/repository/index.html index 0c807dc82..5e3b30f94 100644 --- a/docs/next/tags/repository/index.html +++ b/docs/next/tags/repository/index.html @@ -4,13 +4,13 @@ 3 docs tagged with "repository" | Apiato - +

    3 docs tagged with "repository"

    View All Tags

    Criterias

    To prevent overlap with the L5 Repository documentation, this page

    Models

    Models are responsible for representing the data of the application

    Repositories

    Apiato provides a powerful repository pattern implementation based on the L5 Repository package.

    - + \ No newline at end of file diff --git a/docs/next/tags/request/index.html b/docs/next/tags/request/index.html index ad4233a77..5d1333756 100644 --- a/docs/next/tags/request/index.html +++ b/docs/next/tags/request/index.html @@ -4,13 +4,13 @@ 8 docs tagged with "request" | Apiato - +

    8 docs tagged with "request"

    View All Tags

    Actions

    Actions serve as the embodiment of the application's Use Cases,

    Authorization

    Apiato provides a Role-Based Access Control (RBAC) through its Authorization Container.

    Controllers

    Controllers are tasked with two primary responsibilities:

    Middlewares

    Apiato middlewares are just Laravel Middlewares,

    Policies

    Apiato policies are just Laravel Policies,

    Requests

    Requests components are a way to interact with the current HTTP request

    Routes

    Routes are responsible for mapping incoming HTTP requests to their corresponding controller functions.

    Sub Actions

    SubActions are designed to eliminate code duplication within Actions.

    - + \ No newline at end of file diff --git a/docs/next/tags/response/index.html b/docs/next/tags/response/index.html index 577a1e6e2..59d6a5760 100644 --- a/docs/next/tags/response/index.html +++ b/docs/next/tags/response/index.html @@ -4,13 +4,13 @@ One doc tagged with "response" | Apiato - +

    One doc tagged with "response"

    View All Tags
    - + \ No newline at end of file diff --git a/docs/next/tags/role-based-access-control/index.html b/docs/next/tags/role-based-access-control/index.html index f03d7efd2..40feb704f 100644 --- a/docs/next/tags/role-based-access-control/index.html +++ b/docs/next/tags/role-based-access-control/index.html @@ -4,13 +4,13 @@ One doc tagged with "role-based-access-control" | Apiato - +

    One doc tagged with "role-based-access-control"

    View All Tags
    - + \ No newline at end of file diff --git a/docs/next/tags/route/index.html b/docs/next/tags/route/index.html index 8334a539c..3b39b2f8a 100644 --- a/docs/next/tags/route/index.html +++ b/docs/next/tags/route/index.html @@ -4,13 +4,13 @@ 4 docs tagged with "route" | Apiato - +

    4 docs tagged with "route"

    View All Tags

    Controllers

    Controllers are tasked with two primary responsibilities:

    Middlewares

    Apiato middlewares are just Laravel Middlewares,

    Requests

    Requests components are a way to interact with the current HTTP request

    Routes

    Routes are responsible for mapping incoming HTTP requests to their corresponding controller functions.

    - + \ No newline at end of file diff --git a/docs/next/tags/seeder/index.html b/docs/next/tags/seeder/index.html index 65bf91db2..8547efea4 100644 --- a/docs/next/tags/seeder/index.html +++ b/docs/next/tags/seeder/index.html @@ -4,13 +4,13 @@ 3 docs tagged with "seeder" | Apiato - +

    3 docs tagged with "seeder"

    View All Tags

    Factories

    Apiato factories are just Laravel Factories,

    Migrations

    Apiato migrations are just Laravel Migrations,

    Seeders

    Apiato seeders are just Laravel Seeders,

    - + \ No newline at end of file diff --git a/docs/next/tags/service-provider/index.html b/docs/next/tags/service-provider/index.html index 47262baf0..c16282cdc 100644 --- a/docs/next/tags/service-provider/index.html +++ b/docs/next/tags/service-provider/index.html @@ -4,13 +4,13 @@ 3 docs tagged with "service-provider" | Apiato - +

    3 docs tagged with "service-provider"

    View All Tags

    Events

    Apiato events are just Laravel Events,

    Middlewares

    Apiato middlewares are just Laravel Middlewares,

    - + \ No newline at end of file diff --git a/docs/next/tags/sub-action/index.html b/docs/next/tags/sub-action/index.html index 72d702ba1..8147fec5b 100644 --- a/docs/next/tags/sub-action/index.html +++ b/docs/next/tags/sub-action/index.html @@ -4,13 +4,13 @@ 2 docs tagged with "sub-action" | Apiato - +

    2 docs tagged with "sub-action"

    View All Tags

    Sub Actions

    SubActions are designed to eliminate code duplication within Actions.

    Tasks

    Tasks are specialized classes that hold shared business logic,

    - + \ No newline at end of file diff --git a/docs/next/tags/task/index.html b/docs/next/tags/task/index.html index ba245349e..858584320 100644 --- a/docs/next/tags/task/index.html +++ b/docs/next/tags/task/index.html @@ -4,13 +4,13 @@ 4 docs tagged with "task" | Apiato - +

    4 docs tagged with "task"

    View All Tags

    Criterias

    To prevent overlap with the L5 Repository documentation, this page

    Events

    Apiato events are just Laravel Events,

    Repositories

    Apiato provides a powerful repository pattern implementation based on the L5 Repository package.

    Tasks

    Tasks are specialized classes that hold shared business logic,

    - + \ No newline at end of file diff --git a/docs/next/tags/test/index.html b/docs/next/tags/test/index.html index 7009ed44e..66750dd7f 100644 --- a/docs/next/tags/test/index.html +++ b/docs/next/tags/test/index.html @@ -4,13 +4,13 @@ One doc tagged with "test" | Apiato - +

    One doc tagged with "test"

    View All Tags

    Tests

    Apiato is built with testing in mind.

    - + \ No newline at end of file diff --git a/docs/next/tags/testing/index.html b/docs/next/tags/testing/index.html index 3b775f9f7..86b6a5f92 100644 --- a/docs/next/tags/testing/index.html +++ b/docs/next/tags/testing/index.html @@ -4,13 +4,13 @@ One doc tagged with "testing" | Apiato - +

    One doc tagged with "testing"

    View All Tags

    Factories

    Apiato factories are just Laravel Factories,

    - + \ No newline at end of file diff --git a/docs/next/tags/transformer/index.html b/docs/next/tags/transformer/index.html index 8ae0301d2..187b29b4d 100644 --- a/docs/next/tags/transformer/index.html +++ b/docs/next/tags/transformer/index.html @@ -4,13 +4,13 @@ 2 docs tagged with "transformer" | Apiato - +

    2 docs tagged with "transformer"

    View All Tags

    Controllers

    Controllers are tasked with two primary responsibilities:

    - + \ No newline at end of file diff --git a/docs/next/tags/value/index.html b/docs/next/tags/value/index.html index 655a8f827..98d1d7cd4 100644 --- a/docs/next/tags/value/index.html +++ b/docs/next/tags/value/index.html @@ -4,13 +4,13 @@ One doc tagged with "value" | Apiato - +

    One doc tagged with "value"

    View All Tags

    Values

    Value Objects are short names for known "Value Objects",

    - + \ No newline at end of file diff --git a/docs/next/tags/view/index.html b/docs/next/tags/view/index.html index 5614827d5..1cb850ae8 100644 --- a/docs/next/tags/view/index.html +++ b/docs/next/tags/view/index.html @@ -4,13 +4,13 @@ One doc tagged with "view" | Apiato - +

    One doc tagged with "view"

    View All Tags

    Controllers

    Controllers are tasked with two primary responsibilities:

    - + \ No newline at end of file diff --git a/docs/pacakges/documentation/index.html b/docs/pacakges/documentation/index.html index b7d6b7a56..e16fa58f6 100644 --- a/docs/pacakges/documentation/index.html +++ b/docs/pacakges/documentation/index.html @@ -4,7 +4,7 @@ Documentation | Apiato - + @@ -15,7 +15,7 @@ access-private-docs-permission values in documentation config. By default, users need access-private-docs permission to access private docs.

    Edit Default Generated Values in Templates

    Apiato by defaults generates 2 API documentations, each one has its own apidoc.json file. Both can be modified from the Documentation Container in app/Containers/Vendor/Documentation/ApiDocJs and need Source code modification.

    Edit the Documentation Header

    The header is usually the Overview of your API. It contains Info about authenticating users, making requests, responses, potential errors, rate limiting, pagination, query parameters and anything you want.

    All this information is written in app/Containers/Vendor/Documentation/ApiDocJs/shared/header.template.en.md file, and the same file is used as header for both private and public documentations.

    To edit its content you need to modify its source code and open the markdown file in any markdown editor and edit it.

    You will notice some variables like {{rate-limit}} and {{token-expires}}. Those are replaced when running apiato:apidoc with real values from your application configuration files.

    Feel free to extend them to include more info about your API from the app/Containers/Vendor/Documentation/Tasks/RenderTemplatesTask.php class.

    Localization for Documentation Header

    Default, the documentation title is in English en localization.

    See which locales are supported by going in app/Containers/Vendor/Documentation/ApiDocJs/shared

    There will be some header.template.{locale}.md files in the folder.

    You can change the language by adding APIDOC_LOCALE=ru to the .env file.

    If you didn't find a file with your locale, you can create it. You need to modify its source code and create new file like header.template.cn.md

    - + \ No newline at end of file diff --git a/docs/pacakges/index.html b/docs/pacakges/index.html index 8d6dac154..d7c4f2bc9 100644 --- a/docs/pacakges/index.html +++ b/docs/pacakges/index.html @@ -4,7 +4,7 @@ Overview | Apiato - + @@ -21,7 +21,7 @@ that allows installing/updating containers.
  • You must provide the key extra.apiato.container.name. This key indicates the name of the folder (e.g., container) when installing the package to the app/Containers/Vendor directory. In the shown example, the container would be installed to app/Containers/Vendor/Foo.
  • - + \ No newline at end of file diff --git a/docs/pacakges/localization/index.html b/docs/pacakges/localization/index.html index c9a5faca3..5ce52deae 100644 --- a/docs/pacakges/localization/index.html +++ b/docs/pacakges/localization/index.html @@ -4,7 +4,7 @@ Localization | Apiato - + @@ -41,7 +41,7 @@ language in this specific language (e.g., locale_name => Deutsch). Furthermore, the language name is outputted in the applications default name (e.g., configured in app.locale). This would result in default_name => German.

    The same applies to the regions that are defined (e.g., de-DE). Consequently, this results in locale_name => Deutschland and default_name = Germany.

    Tests

    To change the default language in your tests requests. You can set the env language in the phpunit.xml file.

    - + \ No newline at end of file diff --git a/docs/pacakges/social-authentication/index.html b/docs/pacakges/social-authentication/index.html index b4a02bc19..3fc19b948 100644 --- a/docs/pacakges/social-authentication/index.html +++ b/docs/pacakges/social-authentication/index.html @@ -4,7 +4,7 @@ Social Authentication | Apiato - + @@ -19,7 +19,7 @@ to get the oauth info and user data respectively.

    Social Authentication Container Customization

    You can customize this container by publishing its config and modifying its values

    php artisan vendor:publish

    Config file will be copied to app/Ship/Configs/vendor-socialAuth.php

    Support new Auth Provider

    1. Publish the configs
    2. Create your new auth provider by implementing the App\Containers\Vendor\SocialAuth\Contracts\SocialAuthProvider contract.
      To get an idea about how to implement your own provider you can check out supported providers here app/Containers/Vendor/SocialAuth/SocialAuthProviders.
    3. Add your new provider to providers array in the vendor-socialAuth config.
        'providers' => [
    ...
    'something' => Location\Of\Your\Provider\SomthingSocialAuthProvider::class,
    ],

    Changing default used Repository, Transformer & DB user table name

    This container depends on Apiato default user repository, transformer & database user table name. If you changed those defaults you can update and provide them in the configs.

    - + \ No newline at end of file diff --git a/docs/prologue/contribution-guide/index.html b/docs/prologue/contribution-guide/index.html index 393d4b5d8..3ede6bbac 100644 --- a/docs/prologue/contribution-guide/index.html +++ b/docs/prologue/contribution-guide/index.html @@ -4,7 +4,7 @@ Contribution Guide | Apiato - + @@ -37,7 +37,7 @@ after pull requests are merged. This allows us to focus on the content of the contribution and not the code style.

    Code of Conduct

    The Apiato code of conduct is derived from the Ruby code of conduct. Any violations of the code of conduct may be reported to Mohammad Alavi (mohammad.alavi1990@gmail.com):

    • Participants will be tolerant of opposing views.
    • Participants must ensure that their language and actions are free of personal attacks and disparaging personal remarks.
    • When interpreting the words and actions of others, participants should always assume good intentions.
    • Behavior that can be reasonably considered harassment will not be tolerated.
    - + \ No newline at end of file diff --git a/docs/prologue/release-notes/index.html b/docs/prologue/release-notes/index.html index 2a846d663..052fcc833 100644 --- a/docs/prologue/release-notes/index.html +++ b/docs/prologue/release-notes/index.html @@ -4,7 +4,7 @@ Release Notes | Apiato - + @@ -17,7 +17,7 @@ since major releases of Apiato do include breaking changes. However, we strive to always ensure you may update to a new major release in one day or less.

    Support Policy

    For all Apiato releases, bug fixes are provided for 18 months and security fixes are provided for 2 years.

    VersionPHP (*)ReleaseBug Fixes UntilSecurity Fixes Until
    107.3 - 8.1April 25th, 2021October 25th, 2022April 25th, 2023
    118.0 - 8.2April 27th, 2022October 27th, 2023April 27th, 2024
    128.1 - 8.2June 4th, 2023December 4th, 2024June 4th, 2025
    138.2Q1 2024August 5th, 2025February 3rd, 2026

    (*) Supported PHP versions

    Apiato 12

    Full Changelog: https://github.com/apiato/apiato/compare/v11.3.2...v12.0.0

    PHP 8.1

    Apiato 12.x requires a minimum PHP version of 8.1.

    Breaking Changes

    • Upgraded to Laravel v10 (All Laravel files (e.g. configs, .env, etc...) are now synced with the latest Laravel changes)
    • Updated Composer dependencies to their latest version
    • Laravel Passport route registration & customization has changed. Passport routes are now reside in a dedicated route file (Instead of registering them in the provider).
    • Middleware $routeMiddleware field is renamed to $middlewareAliases
    • Trimmed down the TestCase by removing some useless traits including:
    TestsMockHelperTrait
    TestsResponseHelperTrait
    • encode() method return value has changed -> In case of unencodable value (e.g. null), now returns null instead of ''
    • decode() method return value has changed -> In case of undecodable value (e.g. null), now returns null instead of []
    • StateKeeperTrait is removed from Request

    None Breaking Changes

    • Everything is refactored to use constructor injection instead of directly using the Service Container like so app(CreateUserByCredentialsTask::class)->run()
    • Added more tests and refactored the rest
    • Switched to invokable controllers
    \\ from
    Route::get('profile', [GetAuthenticatedUserController::class, 'getAuthenticatedUser']);
    \\ to
    Route::get('profile', GetAuthenticatedUserController::class);
    • All rotues are moved into the private documentation. e.g. RefreshProxyForWebClient.v1.public.php -> RefreshProxyForWebClient.v1.private.php
    • Added some getter methods to the Request including:
    withUrlParameters()
    getAccessArray()
    getDecodeArray()
    getUrlParametersArray()
    • Added a TestAssertionHelperTrait to the TestCase which provides some usefull assertions

    Bug Fixes

    • withMeta() method on ResponseTrait now correctly includes added meta data
    • Calling invokable controllers from routes #174
    • Exception when try to generate an WEB CRUD Controller from generator #171
    • PHP 8.1 warning on passing null to explode #176
    - + \ No newline at end of file diff --git a/docs/prologue/upgrade-guide/index.html b/docs/prologue/upgrade-guide/index.html index f758e60d2..d68be6f7b 100644 --- a/docs/prologue/upgrade-guide/index.html +++ b/docs/prologue/upgrade-guide/index.html @@ -4,13 +4,13 @@ Upgrade Guide | Apiato - +
    - + \ No newline at end of file diff --git a/docs/security/authentication/index.html b/docs/security/authentication/index.html index 47f104f88..7015fd0c3 100644 --- a/docs/security/authentication/index.html +++ b/docs/security/authentication/index.html @@ -4,7 +4,7 @@ Authentication | Apiato - + @@ -67,7 +67,7 @@ you can navigate to the app/Ship/Providers/RouteServiceProvider.php file and update the LOGIN constant.

    Passing The Access Token

    When calling routes that are protected by Passport, your application's API consumers should specify their access token as a Bearer token in the Authorization header of their request. For example, when using the Guzzle HTTP library:

    use Illuminate\Support\Facades\Http;

    $response = Http::withHeaders([
    'Accept' => 'application/json',
    'Authorization' => 'Bearer '.$accessToken,
    ])->get('http://api.apiato.test/v1/users');

    return $response->json();

    Configuration

    Most of the configuration is done in the app/Ships/Configs/apiato.php file.

    Social Authentication

    For Social Authentication visit the Social Authentication page.

    - + \ No newline at end of file diff --git a/docs/security/authorization/index.html b/docs/security/authorization/index.html index 741b6792c..0bfaf39f1 100644 --- a/docs/security/authorization/index.html +++ b/docs/security/authorization/index.html @@ -4,7 +4,7 @@ Authorization | Apiato - + @@ -19,7 +19,7 @@ you ensure that unauthorized users are denied access before any further processing takes place.

    Default Roles & Permissions

    Apiato comes with some default Roles and Permissions. You can find them in app/Containers/AppSection/Authorization/Data/Seeders. You can use them as a starting point, or delete them and create your own.

    Code Example

    Protecting the delete user endpoint with delete-users permission:

    use App\Ship\Parents\Requests\Request as ParentRequest;

    class DeleteUserRequest extends ParentRequest
    {
    protected array $access = [
    'permissions' => 'delete-users',
    'roles' => '',
    ];

    public function authorize(): bool
    {
    return $this->check([
    'hasAccess',
    ]);
    }
    }

    Authorization failed JSON response:

    {
    "message": "This action is unauthorized.",
    "errors": []
    }
    - + \ No newline at end of file diff --git a/docs/security/email-varification/index.html b/docs/security/email-varification/index.html index d39d2d84d..d9ff8e5de 100644 --- a/docs/security/email-varification/index.html +++ b/docs/security/email-varification/index.html @@ -4,7 +4,7 @@ Email Verification | Apiato - + @@ -22,7 +22,7 @@ when using a load balancer, set the protected $proxies = '*' in the app/Ship/Middlewares/TrustProxies.php or customize it according to your needs.

    - + \ No newline at end of file diff --git a/docs/security/hash-id/index.html b/docs/security/hash-id/index.html index 6c690b179..e7fa302d6 100644 --- a/docs/security/hash-id/index.html +++ b/docs/security/hash-id/index.html @@ -4,7 +4,7 @@ Hash ID | Apiato - + @@ -20,7 +20,7 @@ You can set the HASH_ID_KEY in the .env file to any random string. Apiato defaults to the APP_KEY should this not be set.

    danger

    The HASH_ID_KEY acts as the salt during hashing of the ID. This should never be changed in production as it renders all previously generated IDs impossible to decode.

    Route Model Binding

    Laravel Route Model Binding feature is supported out of the box and Apiato will automatically decode the ID for you.

    - + \ No newline at end of file diff --git a/docs/security/password-reset/index.html b/docs/security/password-reset/index.html index d77971920..61e16092b 100644 --- a/docs/security/password-reset/index.html +++ b/docs/security/password-reset/index.html @@ -4,7 +4,7 @@ Password Reset | Apiato - + @@ -15,7 +15,7 @@ in the allowed-reset-password-urls array within the appSection-authentication configuration.

    Routing

    To request a password reset link, call the /password/forgot endpoint with the user's email address.

    Resetting The Password

    To reset the user's password, call the /password/reset endpoint with the user's email address, new password, and password reset token.

    Process Flow

    1. Add your web app's password reset page URL, for example, https://myapp.com/password/reset, to the allowed-reset-password-urls array within the appSection-authentication configuration.

    2. Call the /password/forgot endpoint with a reset URL of your choice, which should correspond to one of the URLs in the allowed-reset-password-urls array. This endpoint will send the user an email containing a link like this:
      https://myapp.com/password/resetd?email=mohammad.alavi1990@gmail.com&token=51f8d80182f3785648c9b9dc7162719d158fc418b3cca86c14963638ec83d663

    3. When the user clicks on that link, they will be directed to your front-end app's password reset page. From there, you can collect the user's new password and make a call to the /password/reset endpoint with all the required fields to complete the password reset.

    - + \ No newline at end of file diff --git a/docs/security/registration/index.html b/docs/security/registration/index.html index c1c98177c..d00e5d7d4 100644 --- a/docs/security/registration/index.html +++ b/docs/security/registration/index.html @@ -4,13 +4,13 @@ Registration | Apiato - +
    Version: 12.x

    Registration

    Apiato supports two default user registration methods:

    1. Register by Credentials
    2. Register by Social Account

    You can also extend these methods or add new ones to customize your registration process.

    Register by Credentials

    To register a new user, send a POST request to the /register endpoint.

    api.apiato.test/v1/register
    tip

    Don't forget to add Accept: application/json header to your request.

    The /register endpoint expects a string email address and a string password field.

    {
    "email": "gandalg@the.grey",
    "password": "password"
    }

    You should receive a response similar to the following:

    {
    "data": {
    "object": "User",
    "id": "XbPW7awNkzl83LD6",
    "name": null,
    "email": "john@doe.com",
    "email_verified_at": null,
    "gender": null,
    "birth": null
    },
    "meta": {
    "include": [
    "roles",
    "permissions"
    ],
    "custom": []
    }
    }

    Register by Social Account

    (Facebook, Twitter, Google, etc...)

    Checkout the Social Authentication documentation.

    - + \ No newline at end of file diff --git a/docs/tags/action/index.html b/docs/tags/action/index.html index d8e3b8781..513c8e6ce 100644 --- a/docs/tags/action/index.html +++ b/docs/tags/action/index.html @@ -4,13 +4,13 @@ 9 docs tagged with "action" | Apiato - +

    9 docs tagged with "action"

    View All Tags

    Actions

    Actions serve as the embodiment of the application's Use Cases,

    Commands

    Apiato commands are just Laravel Commands,

    Controllers

    Controllers are tasked with two primary responsibilities:

    Criterias

    To prevent overlap with the L5 Repository documentation, this page

    Events

    Apiato events are just Laravel Events,

    Repositories

    Apiato provides a powerful repository pattern implementation based on the L5 Repository package.

    Requests

    Requests components are a way to interact with the current HTTP request

    Sub Actions

    SubActions are designed to eliminate code duplication within Actions.

    Tasks

    Tasks are specialized classes that hold shared business logic,

    - + \ No newline at end of file diff --git a/docs/tags/api-versioning/index.html b/docs/tags/api-versioning/index.html index 67bb7d09d..a0eaf3086 100644 --- a/docs/tags/api-versioning/index.html +++ b/docs/tags/api-versioning/index.html @@ -4,13 +4,13 @@ One doc tagged with "api-versioning" | Apiato - +

    One doc tagged with "api-versioning"

    View All Tags

    API Versioning

    Apiato provides a streamlined approach to implementing API versioning within your application.

    - + \ No newline at end of file diff --git a/docs/tags/architecture/index.html b/docs/tags/architecture/index.html index c77046bba..64f863724 100644 --- a/docs/tags/architecture/index.html +++ b/docs/tags/architecture/index.html @@ -4,13 +4,13 @@ 5 docs tagged with "architecture" | Apiato - +

    5 docs tagged with "architecture"

    View All Tags

    Container

    Containers are at the core of Apiato.

    Porto

    Porto is a modern software architectural pattern that offers developers a comprehensive set of guidelines,

    Request Lifecycle

    When using any tool in the "real world", you feel more confident if you understand how that tool works.

    - + \ No newline at end of file diff --git a/docs/tags/authorization/index.html b/docs/tags/authorization/index.html index b4d710acf..4cb597748 100644 --- a/docs/tags/authorization/index.html +++ b/docs/tags/authorization/index.html @@ -4,13 +4,13 @@ 2 docs tagged with "authorization" | Apiato - +

    2 docs tagged with "authorization"

    View All Tags

    Authorization

    Apiato provides a Role-Based Access Control (RBAC) through its Authorization Container.

    Policies

    Apiato policies are just Laravel Policies,

    - + \ No newline at end of file diff --git a/docs/tags/code-generator/index.html b/docs/tags/code-generator/index.html index 0ff818a4c..ac1c1cf04 100644 --- a/docs/tags/code-generator/index.html +++ b/docs/tags/code-generator/index.html @@ -4,13 +4,13 @@ One doc tagged with "code-generator" | Apiato - +

    One doc tagged with "code-generator"

    View All Tags

    Code Generator

    Apiato comes with a powerful code generator that can help you to generate all the boilerplate code for your containers.

    - + \ No newline at end of file diff --git a/docs/tags/command/index.html b/docs/tags/command/index.html index cf340e4c4..c1958c134 100644 --- a/docs/tags/command/index.html +++ b/docs/tags/command/index.html @@ -4,13 +4,13 @@ One doc tagged with "command" | Apiato - +

    One doc tagged with "command"

    View All Tags

    Commands

    Apiato commands are just Laravel Commands,

    - + \ No newline at end of file diff --git a/docs/tags/component/index.html b/docs/tags/component/index.html index fc1f639c2..a58d0de68 100644 --- a/docs/tags/component/index.html +++ b/docs/tags/component/index.html @@ -4,13 +4,13 @@ 29 docs tagged with "component" | Apiato - +

    29 docs tagged with "component"

    View All Tags

    Actions

    Actions serve as the embodiment of the application's Use Cases,

    Authorization

    Apiato provides a Role-Based Access Control (RBAC) through its Authorization Container.

    Commands

    Apiato commands are just Laravel Commands,

    Configs

    Apiato configs are just Laravel configs, and they function in the exact same way as Laravel configs.

    Controllers

    Controllers are tasked with two primary responsibilities:

    Criterias

    To prevent overlap with the L5 Repository documentation, this page

    Events

    Apiato events are just Laravel Events,

    Exceptions

    Exceptions are used to handle errors and exceptions in the application.

    Factories

    Apiato factories are just Laravel Factories,

    Helpers

    You have the option to create your own global "helper" PHP functions in designated directories, and Apiato will automatically autoload them for you.

    Jobs

    Apiato jobs are just Laravel Jobs,

    Mail

    Apiato mails are just Laravel Mails,

    Middlewares

    Apiato middlewares are just Laravel Middlewares,

    Migrations

    Apiato migrations are just Laravel Migrations,

    Models

    Models are responsible for representing the data of the application

    Notifications

    Apiato notifications are just Laravel Notifications,

    Policies

    Apiato policies are just Laravel Policies,

    Repositories

    Apiato provides a powerful repository pattern implementation based on the L5 Repository package.

    Requests

    Requests components are a way to interact with the current HTTP request

    Routes

    Routes are responsible for mapping incoming HTTP requests to their corresponding controller functions.

    Seeders

    Apiato seeders are just Laravel Seeders,

    Sub Actions

    SubActions are designed to eliminate code duplication within Actions.

    Tasks

    Tasks are specialized classes that hold shared business logic,

    Tests

    Apiato is built with testing in mind.

    Values

    Value Objects are short names for known "Value Objects",

    Views

    Views offer a convenient mechanism for organizing HTML content in separate files.

    - + \ No newline at end of file diff --git a/docs/tags/config/index.html b/docs/tags/config/index.html index f15ac4a12..89db8ec36 100644 --- a/docs/tags/config/index.html +++ b/docs/tags/config/index.html @@ -4,13 +4,13 @@ One doc tagged with "config" | Apiato - +

    One doc tagged with "config"

    View All Tags

    Configs

    Apiato configs are just Laravel configs, and they function in the exact same way as Laravel configs.

    - + \ No newline at end of file diff --git a/docs/tags/container/index.html b/docs/tags/container/index.html index f098f8b82..26216581f 100644 --- a/docs/tags/container/index.html +++ b/docs/tags/container/index.html @@ -4,13 +4,13 @@ One doc tagged with "container" | Apiato - +

    One doc tagged with "container"

    View All Tags

    Container

    Containers are at the core of Apiato.

    - + \ No newline at end of file diff --git a/docs/tags/controller/index.html b/docs/tags/controller/index.html index 19d1abbf7..1d4d6f436 100644 --- a/docs/tags/controller/index.html +++ b/docs/tags/controller/index.html @@ -4,13 +4,13 @@ 8 docs tagged with "controller" | Apiato - +

    8 docs tagged with "controller"

    View All Tags

    Actions

    Actions serve as the embodiment of the application's Use Cases,

    Controllers

    Controllers are tasked with two primary responsibilities:

    Middlewares

    Apiato middlewares are just Laravel Middlewares,

    Requests

    Requests components are a way to interact with the current HTTP request

    Routes

    Routes are responsible for mapping incoming HTTP requests to their corresponding controller functions.

    Sub Actions

    SubActions are designed to eliminate code duplication within Actions.

    Views

    Views offer a convenient mechanism for organizing HTML content in separate files.

    - + \ No newline at end of file diff --git a/docs/tags/criteria/index.html b/docs/tags/criteria/index.html index 2cbdf7e1c..bb175227d 100644 --- a/docs/tags/criteria/index.html +++ b/docs/tags/criteria/index.html @@ -4,13 +4,13 @@ 2 docs tagged with "criteria" | Apiato - +

    2 docs tagged with "criteria"

    View All Tags

    Criterias

    To prevent overlap with the L5 Repository documentation, this page

    Repositories

    Apiato provides a powerful repository pattern implementation based on the L5 Repository package.

    - + \ No newline at end of file diff --git a/docs/tags/etag/index.html b/docs/tags/etag/index.html index 6f117c418..a74523037 100644 --- a/docs/tags/etag/index.html +++ b/docs/tags/etag/index.html @@ -4,13 +4,13 @@ One doc tagged with "etag" | Apiato - +

    One doc tagged with "etag"

    View All Tags

    Etag

    The ETag or entity tag is part of HTTP, the protocol for the World Wide Web.

    - + \ No newline at end of file diff --git a/docs/tags/event/index.html b/docs/tags/event/index.html index dfac8e174..73cf7bf98 100644 --- a/docs/tags/event/index.html +++ b/docs/tags/event/index.html @@ -4,13 +4,13 @@ 2 docs tagged with "event" | Apiato - +

    2 docs tagged with "event"

    View All Tags

    Events

    Apiato events are just Laravel Events,

    - + \ No newline at end of file diff --git a/docs/tags/exception/index.html b/docs/tags/exception/index.html index a8d43d219..3c173bb20 100644 --- a/docs/tags/exception/index.html +++ b/docs/tags/exception/index.html @@ -4,13 +4,13 @@ One doc tagged with "exception" | Apiato - +

    One doc tagged with "exception"

    View All Tags

    Exceptions

    Exceptions are used to handle errors and exceptions in the application.

    - + \ No newline at end of file diff --git a/docs/tags/factory/index.html b/docs/tags/factory/index.html index 17abcdab9..812766df3 100644 --- a/docs/tags/factory/index.html +++ b/docs/tags/factory/index.html @@ -4,13 +4,13 @@ One doc tagged with "factory" | Apiato - +

    One doc tagged with "factory"

    View All Tags

    Factories

    Apiato factories are just Laravel Factories,

    - + \ No newline at end of file diff --git a/docs/tags/framework-feature/index.html b/docs/tags/framework-feature/index.html index d7c0aa6c4..39de08837 100644 --- a/docs/tags/framework-feature/index.html +++ b/docs/tags/framework-feature/index.html @@ -4,13 +4,13 @@ 6 docs tagged with "framework-feature" | Apiato - +

    6 docs tagged with "framework-feature"

    View All Tags

    API Versioning

    Apiato provides a streamlined approach to implementing API versioning within your application.

    Code Generator

    Apiato comes with a powerful code generator that can help you to generate all the boilerplate code for your containers.

    Etag

    The ETag or entity tag is part of HTTP, the protocol for the World Wide Web.

    Profiler

    Profiling is a crucial aspect of optimizing your application's performance

    - + \ No newline at end of file diff --git a/docs/tags/helper/index.html b/docs/tags/helper/index.html index 6921becfe..90d291417 100644 --- a/docs/tags/helper/index.html +++ b/docs/tags/helper/index.html @@ -4,13 +4,13 @@ One doc tagged with "helper" | Apiato - +

    One doc tagged with "helper"

    View All Tags

    Helpers

    You have the option to create your own global "helper" PHP functions in designated directories, and Apiato will automatically autoload them for you.

    - + \ No newline at end of file diff --git a/docs/tags/index.html b/docs/tags/index.html index a7b56cefa..eee51c70d 100644 --- a/docs/tags/index.html +++ b/docs/tags/index.html @@ -4,13 +4,13 @@ Tags | Apiato - + - + \ No newline at end of file diff --git a/docs/tags/job/index.html b/docs/tags/job/index.html index d089b529f..c17f730e5 100644 --- a/docs/tags/job/index.html +++ b/docs/tags/job/index.html @@ -4,13 +4,13 @@ One doc tagged with "job" | Apiato - +

    One doc tagged with "job"

    View All Tags

    Jobs

    Apiato jobs are just Laravel Jobs,

    - + \ No newline at end of file diff --git a/docs/tags/lifecycle/index.html b/docs/tags/lifecycle/index.html index c6548aafb..b1718efe5 100644 --- a/docs/tags/lifecycle/index.html +++ b/docs/tags/lifecycle/index.html @@ -4,13 +4,13 @@ One doc tagged with "lifecycle" | Apiato - +

    One doc tagged with "lifecycle"

    View All Tags

    Request Lifecycle

    When using any tool in the "real world", you feel more confident if you understand how that tool works.

    - + \ No newline at end of file diff --git a/docs/tags/listener/index.html b/docs/tags/listener/index.html index b9b15255e..e793b490d 100644 --- a/docs/tags/listener/index.html +++ b/docs/tags/listener/index.html @@ -4,13 +4,13 @@ One doc tagged with "listener" | Apiato - +

    One doc tagged with "listener"

    View All Tags

    Events

    Apiato events are just Laravel Events,

    - + \ No newline at end of file diff --git a/docs/tags/mail/index.html b/docs/tags/mail/index.html index 1d77a6d7d..48e32bdef 100644 --- a/docs/tags/mail/index.html +++ b/docs/tags/mail/index.html @@ -4,13 +4,13 @@ One doc tagged with "mail" | Apiato - +

    One doc tagged with "mail"

    View All Tags

    Mail

    Apiato mails are just Laravel Mails,

    - + \ No newline at end of file diff --git a/docs/tags/main-component/index.html b/docs/tags/main-component/index.html index 816bf311a..c6bdc9965 100644 --- a/docs/tags/main-component/index.html +++ b/docs/tags/main-component/index.html @@ -4,13 +4,13 @@ 10 docs tagged with "main-component" | Apiato - +

    10 docs tagged with "main-component"

    View All Tags

    Actions

    Actions serve as the embodiment of the application's Use Cases,

    Controllers

    Controllers are tasked with two primary responsibilities:

    Exceptions

    Exceptions are used to handle errors and exceptions in the application.

    Models

    Models are responsible for representing the data of the application

    Requests

    Requests components are a way to interact with the current HTTP request

    Routes

    Routes are responsible for mapping incoming HTTP requests to their corresponding controller functions.

    Sub Actions

    SubActions are designed to eliminate code duplication within Actions.

    Tasks

    Tasks are specialized classes that hold shared business logic,

    Views

    Views offer a convenient mechanism for organizing HTML content in separate files.

    - + \ No newline at end of file diff --git a/docs/tags/middleware/index.html b/docs/tags/middleware/index.html index 3071b8819..38dd3b229 100644 --- a/docs/tags/middleware/index.html +++ b/docs/tags/middleware/index.html @@ -4,13 +4,13 @@ 2 docs tagged with "middleware" | Apiato - +

    2 docs tagged with "middleware"

    View All Tags

    Middlewares

    Apiato middlewares are just Laravel Middlewares,

    - + \ No newline at end of file diff --git a/docs/tags/migration/index.html b/docs/tags/migration/index.html index 7d4705f32..b1bb627aa 100644 --- a/docs/tags/migration/index.html +++ b/docs/tags/migration/index.html @@ -4,13 +4,13 @@ 2 docs tagged with "migration" | Apiato - +

    2 docs tagged with "migration"

    View All Tags

    Migrations

    Apiato migrations are just Laravel Migrations,

    Seeders

    Apiato seeders are just Laravel Seeders,

    - + \ No newline at end of file diff --git a/docs/tags/model/index.html b/docs/tags/model/index.html index de24af826..68dedc723 100644 --- a/docs/tags/model/index.html +++ b/docs/tags/model/index.html @@ -4,13 +4,13 @@ 4 docs tagged with "model" | Apiato - +

    4 docs tagged with "model"

    View All Tags

    Factories

    Apiato factories are just Laravel Factories,

    Models

    Models are responsible for representing the data of the application

    Values

    Value Objects are short names for known "Value Objects",

    - + \ No newline at end of file diff --git a/docs/tags/notification/index.html b/docs/tags/notification/index.html index f8dc8eca9..a2556f7dd 100644 --- a/docs/tags/notification/index.html +++ b/docs/tags/notification/index.html @@ -4,13 +4,13 @@ One doc tagged with "notification" | Apiato - +

    One doc tagged with "notification"

    View All Tags

    Notifications

    Apiato notifications are just Laravel Notifications,

    - + \ No newline at end of file diff --git a/docs/tags/optional-component/index.html b/docs/tags/optional-component/index.html index 73eda3bcf..6dc7f0598 100644 --- a/docs/tags/optional-component/index.html +++ b/docs/tags/optional-component/index.html @@ -4,13 +4,13 @@ 18 docs tagged with "optional-component" | Apiato - +

    18 docs tagged with "optional-component"

    View All Tags

    Authorization

    Apiato provides a Role-Based Access Control (RBAC) through its Authorization Container.

    Commands

    Apiato commands are just Laravel Commands,

    Configs

    Apiato configs are just Laravel configs, and they function in the exact same way as Laravel configs.

    Criterias

    To prevent overlap with the L5 Repository documentation, this page

    Events

    Apiato events are just Laravel Events,

    Factories

    Apiato factories are just Laravel Factories,

    Helpers

    You have the option to create your own global "helper" PHP functions in designated directories, and Apiato will automatically autoload them for you.

    Jobs

    Apiato jobs are just Laravel Jobs,

    Mail

    Apiato mails are just Laravel Mails,

    Middlewares

    Apiato middlewares are just Laravel Middlewares,

    Migrations

    Apiato migrations are just Laravel Migrations,

    Notifications

    Apiato notifications are just Laravel Notifications,

    Policies

    Apiato policies are just Laravel Policies,

    Repositories

    Apiato provides a powerful repository pattern implementation based on the L5 Repository package.

    Seeders

    Apiato seeders are just Laravel Seeders,

    Tests

    Apiato is built with testing in mind.

    Values

    Value Objects are short names for known "Value Objects",

    - + \ No newline at end of file diff --git a/docs/tags/policy/index.html b/docs/tags/policy/index.html index 178bff5d9..b05bd8b42 100644 --- a/docs/tags/policy/index.html +++ b/docs/tags/policy/index.html @@ -4,13 +4,13 @@ 2 docs tagged with "policy" | Apiato - +

    2 docs tagged with "policy"

    View All Tags

    Authorization

    Apiato provides a Role-Based Access Control (RBAC) through its Authorization Container.

    Policies

    Apiato policies are just Laravel Policies,

    - + \ No newline at end of file diff --git a/docs/tags/porto/index.html b/docs/tags/porto/index.html index 1e7d5763e..3af5554e8 100644 --- a/docs/tags/porto/index.html +++ b/docs/tags/porto/index.html @@ -4,13 +4,13 @@ 5 docs tagged with "porto" | Apiato - +

    5 docs tagged with "porto"

    View All Tags

    Container

    Containers are at the core of Apiato.

    Porto

    Porto is a modern software architectural pattern that offers developers a comprehensive set of guidelines,

    Request Lifecycle

    When using any tool in the "real world", you feel more confident if you understand how that tool works.

    - + \ No newline at end of file diff --git a/docs/tags/profiler/index.html b/docs/tags/profiler/index.html index c6bca6a94..873752733 100644 --- a/docs/tags/profiler/index.html +++ b/docs/tags/profiler/index.html @@ -4,13 +4,13 @@ One doc tagged with "profiler" | Apiato - +

    One doc tagged with "profiler"

    View All Tags

    Profiler

    Profiling is a crucial aspect of optimizing your application's performance

    - + \ No newline at end of file diff --git a/docs/tags/queue/index.html b/docs/tags/queue/index.html index 58ed50d7f..e310f0fc1 100644 --- a/docs/tags/queue/index.html +++ b/docs/tags/queue/index.html @@ -4,13 +4,13 @@ 3 docs tagged with "queue" | Apiato - +

    3 docs tagged with "queue"

    View All Tags

    Jobs

    Apiato jobs are just Laravel Jobs,

    Mail

    Apiato mails are just Laravel Mails,

    Notifications

    Apiato notifications are just Laravel Notifications,

    - + \ No newline at end of file diff --git a/docs/tags/rate-limiting/index.html b/docs/tags/rate-limiting/index.html index f99fdf78c..3e1272e16 100644 --- a/docs/tags/rate-limiting/index.html +++ b/docs/tags/rate-limiting/index.html @@ -4,13 +4,13 @@ One doc tagged with "rate-limiting" | Apiato - +

    One doc tagged with "rate-limiting"

    View All Tags
    - + \ No newline at end of file diff --git a/docs/tags/repository/index.html b/docs/tags/repository/index.html index 703a1d297..9583f9fd1 100644 --- a/docs/tags/repository/index.html +++ b/docs/tags/repository/index.html @@ -4,13 +4,13 @@ 3 docs tagged with "repository" | Apiato - +

    3 docs tagged with "repository"

    View All Tags

    Criterias

    To prevent overlap with the L5 Repository documentation, this page

    Models

    Models are responsible for representing the data of the application

    Repositories

    Apiato provides a powerful repository pattern implementation based on the L5 Repository package.

    - + \ No newline at end of file diff --git a/docs/tags/request/index.html b/docs/tags/request/index.html index 3a4e20dbc..d618031da 100644 --- a/docs/tags/request/index.html +++ b/docs/tags/request/index.html @@ -4,13 +4,13 @@ 8 docs tagged with "request" | Apiato - +

    8 docs tagged with "request"

    View All Tags

    Actions

    Actions serve as the embodiment of the application's Use Cases,

    Authorization

    Apiato provides a Role-Based Access Control (RBAC) through its Authorization Container.

    Controllers

    Controllers are tasked with two primary responsibilities:

    Middlewares

    Apiato middlewares are just Laravel Middlewares,

    Policies

    Apiato policies are just Laravel Policies,

    Requests

    Requests components are a way to interact with the current HTTP request

    Routes

    Routes are responsible for mapping incoming HTTP requests to their corresponding controller functions.

    Sub Actions

    SubActions are designed to eliminate code duplication within Actions.

    - + \ No newline at end of file diff --git a/docs/tags/response/index.html b/docs/tags/response/index.html index 6e176fc53..1488563ec 100644 --- a/docs/tags/response/index.html +++ b/docs/tags/response/index.html @@ -4,13 +4,13 @@ One doc tagged with "response" | Apiato - +

    One doc tagged with "response"

    View All Tags
    - + \ No newline at end of file diff --git a/docs/tags/role-based-access-control/index.html b/docs/tags/role-based-access-control/index.html index 992835f2e..17411acb2 100644 --- a/docs/tags/role-based-access-control/index.html +++ b/docs/tags/role-based-access-control/index.html @@ -4,13 +4,13 @@ One doc tagged with "role-based-access-control" | Apiato - +

    One doc tagged with "role-based-access-control"

    View All Tags
    - + \ No newline at end of file diff --git a/docs/tags/route/index.html b/docs/tags/route/index.html index a36cf16dc..6eb52ad79 100644 --- a/docs/tags/route/index.html +++ b/docs/tags/route/index.html @@ -4,13 +4,13 @@ 4 docs tagged with "route" | Apiato - +

    4 docs tagged with "route"

    View All Tags

    Controllers

    Controllers are tasked with two primary responsibilities:

    Middlewares

    Apiato middlewares are just Laravel Middlewares,

    Requests

    Requests components are a way to interact with the current HTTP request

    Routes

    Routes are responsible for mapping incoming HTTP requests to their corresponding controller functions.

    - + \ No newline at end of file diff --git a/docs/tags/seeder/index.html b/docs/tags/seeder/index.html index 31aa62de9..0dd9b9a92 100644 --- a/docs/tags/seeder/index.html +++ b/docs/tags/seeder/index.html @@ -4,13 +4,13 @@ 3 docs tagged with "seeder" | Apiato - +

    3 docs tagged with "seeder"

    View All Tags

    Factories

    Apiato factories are just Laravel Factories,

    Migrations

    Apiato migrations are just Laravel Migrations,

    Seeders

    Apiato seeders are just Laravel Seeders,

    - + \ No newline at end of file diff --git a/docs/tags/service-provider/index.html b/docs/tags/service-provider/index.html index 5a4aa24d5..99a6f65e0 100644 --- a/docs/tags/service-provider/index.html +++ b/docs/tags/service-provider/index.html @@ -4,13 +4,13 @@ 3 docs tagged with "service-provider" | Apiato - +

    3 docs tagged with "service-provider"

    View All Tags

    Events

    Apiato events are just Laravel Events,

    Middlewares

    Apiato middlewares are just Laravel Middlewares,

    - + \ No newline at end of file diff --git a/docs/tags/sub-action/index.html b/docs/tags/sub-action/index.html index 2b25aa7e4..bd0ae9943 100644 --- a/docs/tags/sub-action/index.html +++ b/docs/tags/sub-action/index.html @@ -4,13 +4,13 @@ 2 docs tagged with "sub-action" | Apiato - +

    2 docs tagged with "sub-action"

    View All Tags

    Sub Actions

    SubActions are designed to eliminate code duplication within Actions.

    Tasks

    Tasks are specialized classes that hold shared business logic,

    - + \ No newline at end of file diff --git a/docs/tags/task/index.html b/docs/tags/task/index.html index 70b49e6bd..502acd6b1 100644 --- a/docs/tags/task/index.html +++ b/docs/tags/task/index.html @@ -4,13 +4,13 @@ 4 docs tagged with "task" | Apiato - +

    4 docs tagged with "task"

    View All Tags

    Criterias

    To prevent overlap with the L5 Repository documentation, this page

    Events

    Apiato events are just Laravel Events,

    Repositories

    Apiato provides a powerful repository pattern implementation based on the L5 Repository package.

    Tasks

    Tasks are specialized classes that hold shared business logic,

    - + \ No newline at end of file diff --git a/docs/tags/test/index.html b/docs/tags/test/index.html index bca01e3bc..90ed4e16e 100644 --- a/docs/tags/test/index.html +++ b/docs/tags/test/index.html @@ -4,13 +4,13 @@ One doc tagged with "test" | Apiato - +

    One doc tagged with "test"

    View All Tags

    Tests

    Apiato is built with testing in mind.

    - + \ No newline at end of file diff --git a/docs/tags/testing/index.html b/docs/tags/testing/index.html index 111f1da1d..11aa8cea7 100644 --- a/docs/tags/testing/index.html +++ b/docs/tags/testing/index.html @@ -4,13 +4,13 @@ One doc tagged with "testing" | Apiato - +

    One doc tagged with "testing"

    View All Tags

    Factories

    Apiato factories are just Laravel Factories,

    - + \ No newline at end of file diff --git a/docs/tags/transformer/index.html b/docs/tags/transformer/index.html index dade78abc..1c2602f90 100644 --- a/docs/tags/transformer/index.html +++ b/docs/tags/transformer/index.html @@ -4,13 +4,13 @@ 2 docs tagged with "transformer" | Apiato - +

    2 docs tagged with "transformer"

    View All Tags

    Controllers

    Controllers are tasked with two primary responsibilities:

    - + \ No newline at end of file diff --git a/docs/tags/value/index.html b/docs/tags/value/index.html index c182b13ee..0948c6edb 100644 --- a/docs/tags/value/index.html +++ b/docs/tags/value/index.html @@ -4,13 +4,13 @@ One doc tagged with "value" | Apiato - +

    One doc tagged with "value"

    View All Tags

    Values

    Value Objects are short names for known "Value Objects",

    - + \ No newline at end of file diff --git a/docs/tags/view/index.html b/docs/tags/view/index.html index 5d61ca0e0..ec003ba92 100644 --- a/docs/tags/view/index.html +++ b/docs/tags/view/index.html @@ -4,13 +4,13 @@ One doc tagged with "view" | Apiato - +

    One doc tagged with "view"

    View All Tags

    Controllers

    Controllers are tasked with two primary responsibilities:

    - + \ No newline at end of file diff --git a/index.html b/index.html index 6315bf7c4..49bcbc7ba 100644 --- a/index.html +++ b/index.html @@ -4,13 +4,13 @@ Apiato - +

    Unearth Scale, Ignite Speed

    Conquer Complexity

    Apiato stands as a scalable and enterprise-grade framework layered atop Laravel, addressing a crucial gap in the development of expansive applications: the Architecture.

    Features

    Detailed Documentation, with Examples, Definitions, Principles and Guidelines.

    Powerful Code Generator

    API Documentations Generator
    (using APIDocJS)

    API Versioning

    OAuth2.0 Authentication
    (using Laravel Passport)

    Hash ID Support

    Role-Based Access Control (RBAC)
    (using Laravel Permission)

    Query Parameters
    (orderBy, sortedBy, etc...)

    Pagination, Limit & Offset

    Data Caching

    Shallow ETag Support

    Performance Profiler

    Localization

    Social Authentication
    (using Laravel Socialite)

    Useful Tests Helpers

    Multiple Response Payload Formats
    (JSON, Data Array & Pure Data)

    - + \ No newline at end of file