diff --git a/ai/cs/@home.texy b/ai/cs/@home.texy new file mode 100644 index 0000000000..e2385cdf80 --- /dev/null +++ b/ai/cs/@home.texy @@ -0,0 +1,11 @@ +Nette AI +******** + +- [Introduction |guide] +- [Getting Started |getting-started] +- [MCP Inspector |mcp-inspector] +- [Claude Code |claude-code] +- [Tips & Best Practices |tips] + +{{maintitle: Nette AI – Vibe Coding with Nette Framework}} +{{description: Build Nette applications with AI assistance. MCP Inspector gives any AI tool deep knowledge of your application's DI container, database, routing, and errors. No hallucinations, just clean code.}} diff --git a/ai/cs/@meta.texy b/ai/cs/@meta.texy new file mode 100644 index 0000000000..e06cc9886c --- /dev/null +++ b/ai/cs/@meta.texy @@ -0,0 +1 @@ +{{sitename: Nette AI}} diff --git a/ai/en/@home.texy b/ai/en/@home.texy new file mode 100644 index 0000000000..e2385cdf80 --- /dev/null +++ b/ai/en/@home.texy @@ -0,0 +1,11 @@ +Nette AI +******** + +- [Introduction |guide] +- [Getting Started |getting-started] +- [MCP Inspector |mcp-inspector] +- [Claude Code |claude-code] +- [Tips & Best Practices |tips] + +{{maintitle: Nette AI – Vibe Coding with Nette Framework}} +{{description: Build Nette applications with AI assistance. MCP Inspector gives any AI tool deep knowledge of your application's DI container, database, routing, and errors. No hallucinations, just clean code.}} diff --git a/ai/en/@left-menu.texy b/ai/en/@left-menu.texy new file mode 100644 index 0000000000..54132f474a --- /dev/null +++ b/ai/en/@left-menu.texy @@ -0,0 +1,5 @@ +- [Introduction |guide] +- [Getting Started |getting-started] +- [MCP Inspector |mcp-inspector] +- [Claude Code |claude-code] +- [Tips & Best Practices |tips] diff --git a/ai/en/@meta.texy b/ai/en/@meta.texy new file mode 100644 index 0000000000..e06cc9886c --- /dev/null +++ b/ai/en/@meta.texy @@ -0,0 +1 @@ +{{sitename: Nette AI}} diff --git a/ai/en/claude-code.texy b/ai/en/claude-code.texy new file mode 100644 index 0000000000..f12fa5faf1 --- /dev/null +++ b/ai/en/claude-code.texy @@ -0,0 +1,251 @@ +Claude Code Plugin +****************** + +
+ +The Nette plugin gives Claude deep knowledge of the framework. Instead of generic PHP advice, you get recommendations that follow Nette conventions – from presenters and forms to Latte templates and database queries. + +The plugin includes: +- **10 skills** covering all major areas of Nette development +- **Automatic validation** that catches errors in Latte and NEON files +- **MCP Inspector integration** for real-time application introspection + +
+ + +Installation +============ + +If you haven't installed Claude Code yet, see the [complete setup guide |getting-started]. Once Claude Code is running, install the Nette plugin: + +```shell +/plugin marketplace add nette/claude-code +/plugin install nette@nette +``` + + +How Skills Work +=============== + +You don't need to activate skills manually. They turn on automatically based on what you're talking about. + +- Ask about "presenter structure" → the `nette-architecture` skill activates +- Ask about "form validation" → the `nette-forms` skill activates +- Ask about "Latte filters" → the `latte-templates` skill activates + +This means you get relevant, context-aware help without having to think about which skill you need. + + +Available Skills +================ + +Here's what each skill covers: + + +nette-architecture +------------------ + +When you're designing your application structure, this skill guides you through: + +- **Directory organization** – Where to put presenters, services, entities, and components +- **Module design** – How to split your application into logical modules (Admin, Front, Api) +- **Presenter patterns** – When to use base presenters, how to handle authentication +- **Evolution strategy** – Start minimal, grow organically, refactor when needed + +The key principle: Don't over-engineer. Create subdirectories when you have 5+ related files, not before. + + +nette-configuration +------------------- + +Everything about the DI container and NEON configuration: + +- **Service registration** – How to define services in `services.neon` +- **Autowiring** – When it works automatically and when you need explicit configuration +- **Parameters** – How to use configuration parameters across your application +- **Extensions** – Working with DI extensions from Nette and third parties + + +nette-database +-------------- + +Covers both the raw SQL approach and the Database Explorer: + +- **Database Explorer** – Using `Selection` for queries, `ActiveRow` for entities +- **Entity conventions** – The `Row` suffix pattern, type hints with `@property-read` +- **Relationships** – Navigating foreign keys with colon notation +- **When to use what** – Explorer for CRUD, raw SQL for complex analytics + +Example: Claude knows that `->where('category.slug', $slug)` automatically joins the category table. + + +nette-forms +----------- + +Creating and handling forms the Nette way: + +- **Controls** – All built-in controls from text inputs to file uploads +- **Validation** – Built-in rules, custom validators, conditional validation +- **Rendering** – Manual rendering, Bootstrap integration, custom renderers +- **Patterns** – Create/edit forms, form components, AJAX submissions + + +nette-schema +------------ + +Data validation and normalization with the Schema component: + +- **Expect class** – Building validation schemas for arrays and objects +- **Configuration schemas** – Validating NEON configuration in DI extensions +- **Type coercion** – Automatic conversion of strings to integers, dates, etc. +- **Custom validators** – Adding your own validation rules + +Example: Claude knows how to create schemas like: + +```php +$schema = Expect::structure([ + 'name' => Expect::string()->required(), + 'age' => Expect::int()->min(0)->max(120), + 'email' => Expect::string(), + 'roles' => Expect::listOf('string')->default([]), +]); +``` + + +nette-testing +------------- + +Writing tests with Nette Tester: + +- **Test structure** – The `.phpt` format, `@testCase` annotation, file organization +- **Assertions** – All `Assert::*` methods: `same()`, `equal()`, `exception()`, `match()`, and more +- **Fixtures** – Setting up test data, mocking dependencies, database transactions +- **Running tests** – Command-line options, parallel execution, code coverage + +Example: Claude can generate proper test files: + +```php +/** @testCase */ +class UserServiceTest extends TestCase +{ + public function testCreateUser(): void + { + $service = new UserService($this->mockDatabase()); + $user = $service->create(['name' => 'John']); + Assert::same('John', $user->name); + } +} +``` + + +nette-utils +----------- + +The utility classes that make PHP development easier: + +- **Arrays** – `Nette\Utils\Arrays` with `get()`, `getRef()`, `map()`, `flatten()`, and more +- **Strings** – Unicode-safe operations: `webalize()`, `truncate()`, `contains()`, `startsWith()` +- **Finder** – File system traversal with filtering by name, size, date +- **Image** – Resize, crop, sharpen with automatic format detection +- **Json** – Safe JSON encoding/decoding with proper error handling +- **Validators** – Email, URL, numeric validation helpers +- **DateTime** – Immutable date/time with Czech locale support + + +frontend-development +-------------------- + +Integrating frontend tools with Nette: + +- **Vite** – Setting up Vite for modern JavaScript/TypeScript development, HMR configuration +- **Nette Assets** – Using the asset system for cache-busted URLs in production +- **Tailwind CSS** – Configuration for Tailwind with Latte templates, purging unused styles +- **ESLint & Prettier** – Code quality tools integration +- **Build scripts** – npm/package.json scripts for development and production builds + +Claude can help configure `vite.config.js` to work with Nette's directory structure and generate proper asset references in Latte templates. + + +latte-templates +--------------- + +Everything about the Latte templating engine: + +- **Syntax** – Tags, filters, blocks, and inheritance +- **Security** – Auto-escaping, content-aware output +- **Custom filters** – Creating and registering your own filters +- **Template classes** – Using typed templates for better IDE support + + +neon-format +----------- + +The NEON configuration format: + +- **Syntax** – Mappings, sequences, entities, and multiline strings +- **Common patterns** – Service definitions, parameter references +- **Debugging** – Finding and fixing syntax errors + + +Automatic Validation +==================== + +One of the most useful features is automatic validation. After every file edit, the plugin checks for errors: + +| What | How It Works | +|------|--------------| +| **Latte templates** | Runs `latte-lint` to check syntax after every `.latte` edit | +| **NEON files** | Validates NEON syntax after every `.neon` edit | +| **Tracy errors** | Watches the exception log and alerts Claude about new errors | + +If there's a syntax error in your Latte template, Claude knows about it immediately and can suggest a fix. No more discovering errors in the browser. + + +Plugin for Framework Contributors +================================= + +If you're contributing to Nette itself, there's an additional plugin with coding standards: + +```shell +/plugin install nette-dev@nette +``` + +| Skill | What It Covers | +|-------|----------------| +| `php-coding-standards` | Nette's PHP coding style – indentation, naming, structure | +| `php-doc` | PHPDoc conventions – when to document, what format to use | +| `commit-messages` | How to write commit messages for Nette repositories | + + +Automatic PHP Style Fixing +========================== + +For automatic code style fixing after every PHP file edit, install the optional php-fixer plugin: + +```shell +/plugin install php-fixer@nette +/install-php-fixer +``` + +The second command installs `nette/coding-standard` globally. After that, every PHP file you edit will be automatically formatted according to Nette coding standards. + + +MCP Inspector Integration +========================= + +The plugin works even better with [MCP Inspector |mcp-inspector] – a tool that lets Claude see your actual application state. With MCP Inspector, Claude can: + +- Query your real database schema instead of guessing +- List your registered DI services and their configuration +- Read Tracy error logs for debugging +- Match URLs to presenters using your actual routes + +Install it with a single command: + +```shell +/install-mcp-inspector +``` + +Then restart Claude Code. See the [MCP Inspector documentation |mcp-inspector] for all 20 available tools. + +{{composer: nette/claude-code}} diff --git a/ai/en/getting-started.texy b/ai/en/getting-started.texy new file mode 100644 index 0000000000..fa20b5da1f --- /dev/null +++ b/ai/en/getting-started.texy @@ -0,0 +1,260 @@ +Getting Started +*************** + +
+ +Ready to try [vibe coding |guide] with Nette? This guide walks you through the complete setup: + +- Choosing and installing an AI tool +- Setting up MCP Inspector so AI can see your application +- Making your first AI-assisted changes + +The whole process takes about 10 minutes. Let's get started! + +
+ + +Choosing Your AI Tool +===================== + +Nette AI tools work with any MCP-compatible AI assistant. We recommend **Claude Code** for the best experience – it has a dedicated Nette plugin with deep framework knowledge and automatic code validation. + +Other options include **Cursor**, **VS Code with Continue**, and other MCP-compatible tools. See [Other AI Tools |#other-ai-tools] at the end of this guide. + + +What You'll Need +================ + +Before we begin, make sure you have: + +- **A Nette project** – existing or new (`composer create-project nette/web-project`) +- **PHP 8.2+** – required for MCP Inspector +- **An AI tool** – we'll install Claude Code below (Claude Pro costs $20/month) + + +Installation on macOS and Linux +=============================== + +```shell +curl -fsSL https://claude.ai/install.sh | bash +``` + +On macOS, you can alternatively use Homebrew: + +```shell +brew install --cask claude-code +``` + +After installation, skip to [Starting Claude Code |#starting-claude-code]. + + +Installation on Windows via WSL +=============================== + +Claude Code requires a Unix environment. On Windows, use WSL: + +```shell +wsl --install +``` + +This installs Ubuntu. **Restart your computer** after installation. + +After restart, launch Ubuntu: + +```shell +ubuntu +``` + +First launch will ask for a username and password – you'll need it for `sudo` later. + +Installing Claude Code in WSL in the Ubuntu terminal: + +```shell +curl -fsSL https://claude.ai/install.sh | bash +``` + +Your Windows drives are mounted under `/mnt/`: +- `C:\Users\Jan\Projects` → `/mnt/c/Users/Jan/Projects` +- `D:\Work` → `/mnt/d/Work` + +From Windows, access Linux files via `\\wsl$\Ubuntu\home\username` in Explorer. + + +Starting Claude Code +==================== + +Great, you have Claude Code installed! Let's start it up. + +Navigate to your project directory: + +```shell +# Windows (WSL) +cd /mnt/c/Users/Jan/Projects/my-app + +# macOS/Linux +cd ~/projects/my-app +``` + +Start Claude Code: + +```shell +claude +``` + +The first time you run it, Claude Code will ask you to authenticate. It will open a browser window where you can log in to your Anthropic account. After successful authentication, you'll see the `claude>` prompt and you're ready to go. + +You can also use Claude Code "on the web":https://claude.ai/code or via the "desktop app":https://claude.com/download, but local installation provides the best experience with direct file access. + + +Adding the Nette Plugin +======================= + +Now let's give Claude deep knowledge of Nette. First, add the Nette marketplace and enable auto-updating: + +```shell +/plugin marketplace add nette/claude-code +``` + +Then install the plugin: + +```shell +/plugin install nette@nette +``` + +That's it! The plugin is now active. It includes 10 specialized skills that automatically activate based on what you're working on. When you ask about forms, it knows about Nette Forms. When you ask about templates, it knows about Latte. + + +Setting Up MCP Inspector +======================== + +The final piece is MCP Inspector, which lets Claude see your actual application – your services, database schema, routes, and error logs. + +The easiest way to install it is through Claude Code: + +```shell +/install-mcp-inspector +``` + +This command adds the `nette/mcp-inspector` package to your project and configures everything automatically. + +Alternatively, you can install it manually with Composer: + +```shell +composer require nette/mcp-inspector +``` + +**Important:** After installing MCP Inspector, restart Claude Code (type `/exit` and run `claude` again) to activate the connection. + + +Testing Your Setup +================== + +Let's verify everything works. Try these prompts: + + +Test the Plugin Knowledge +------------------------- + +Type: + +``` +What's the recommended directory structure for a Nette application? +``` + +Claude should respond with detailed information about presenters, models, templates, and configuration – knowledge that comes from the `nette-architecture` skill. + + +Test MCP Inspector +------------------ + +Type: + +``` +What services do I have registered in my DI container? +``` + +If MCP Inspector is working, Claude will call `di_get_services()` and show you the actual services from your application. If you see a list of your real services, congratulations – everything is set up correctly! + + +Test Database Introspection +--------------------------- + +If your application uses a database, try: + +``` +What tables do I have? Show me the columns in the user table. +``` + + +Your First Real Task +==================== + +Now that everything is set up, let's do something useful. Try this prompt: + +``` +I need a simple ArticlePresenter with list and detail actions. +Generate the presenter, templates, and tell me what routes I need. +``` + +Watch as Claude generates a complete, working presenter following Nette conventions. It will: +- Create the presenter class with proper type hints +- Generate Latte templates for both actions +- Suggest the appropriate route configuration + +If you have MCP Inspector set up and an `article` table in your database, try: + +``` +Look at my article table and generate an ArticleRow entity with proper type hints. +``` + + +Other AI Tools +============== + +While we recommend Claude Code for the best Nette experience, MCP Inspector works with any MCP-compatible tool. + + +Cursor +------ + +Cursor is a popular AI-first code editor. To use MCP Inspector with Cursor: + +1. Install MCP Inspector: `composer require nette/mcp-inspector` +2. Create `.cursor/mcp.json` in your project: + +```json +{ + "mcpServers": { + "nette-inspector": { + "command": "php", + "args": ["vendor/bin/mcp-inspector"] + } + } +} +``` + +3. Restart Cursor + +Note: Cursor doesn't have the Nette-specific skills that the Claude Code plugin provides, but MCP Inspector will still give it access to your application's services, database, routes, and logs. + + +VS Code + Continue +------------------ + +Continue is an open-source AI coding assistant for VS Code. Configure MCP Inspector in Continue's settings following their MCP documentation. + + +Other MCP Tools +--------------- + +Any tool supporting the Model Context Protocol can use MCP Inspector. See the [MCP Inspector manual configuration |mcp-inspector#manual-mcp-configuration] for setup instructions. + + +What's Next +=========== + +You're now ready for AI-assisted Nette development! Here's where to go from here: + +- [MCP Inspector |mcp-inspector] – Learn about all 20 introspection tools +- [Claude Code Plugin |claude-code] – Explore all 13 skills (Claude Code users) +- [Tips & Best Practices |tips] – Get the most out of your AI assistant diff --git a/ai/en/guide.texy b/ai/en/guide.texy new file mode 100644 index 0000000000..b0d98486c5 --- /dev/null +++ b/ai/en/guide.texy @@ -0,0 +1,128 @@ +Vibe Coding +*********** + +
+ +Vibe coding is a new way of programming where you describe what you want in plain language and AI writes the code for you. Nette is ideal for this style of development – strict dependency injection, strong typing, and clear conventions allow AI to generate precise, working code. + +- **MCP Inspector** – Gives any AI tool real-time access to your application +- **Claude Code Plugin** – Deep Nette knowledge for Claude Code users +- **Best Practices** – Proven patterns for effective AI collaboration + +
+ + +What is Vibe Coding? +==================== + +"The hottest new programming language is English." + +That's the core idea behind vibe coding – instead of writing every line yourself, you describe your intent and let AI handle the implementation. Want a presenter for managing products? Just say so. Need a form with validation? Describe the fields and rules. + +But here's the important part: **AI doesn't replace programmers**. It's a powerful assistant that accelerates routine work: + +- Generate boilerplate code (presenters, forms, entities) in seconds +- Understand existing code and explain how it works +- Find bugs and suggest fixes +- Write tests based on your implementation + +The catch? AI doesn't truly know your application. It sees only what you show it and guesses the rest based on patterns it learned during training. That's where Nette AI tools come in. + + +Why Nette is Perfect for AI +=========================== + +Not all frameworks work equally well with AI. Nette has properties that make it exceptionally suited for AI-assisted development: + +**Strict Dependency Injection** + +In Nette, all services are registered in the DI container. AI can inspect exactly what services exist and how they're configured – no guessing required. + +**Strong Typing** + +Type hints on methods and properties mean AI generates code that actually works. Fewer runtime errors, less debugging. + +**Clear Conventions** + +Presenters, components, templates – everything has its place. AI can follow these patterns and produce code that looks like it was written by an experienced Nette developer. + +The key principle: + +.**"Without MCP, AI guesses. With MCP, AI knows."** + + +How It Works +============ + +The magic happens through **MCP (Model Context Protocol)** – an open standard for connecting AI assistants to external data sources. Instead of guessing based on training data, AI can query your actual application state. + +Here's the flow: + +1. **You** describe what you want: "Create an entity for the product table" +2. **AI tool** (Claude, Cursor, etc.) needs to know your database schema +3. **MCP Inspector** queries your application and returns the actual schema +4. **AI** generates code that matches your real database + +No hallucinations. No guessing. Just accurate code. + + +Nette AI Tools +============== + + +MCP Inspector +------------- + +The core of Nette's AI integration. MCP Inspector is an MCP server that gives **any compatible AI tool** real-time access to your application: + +| What AI Can See | Examples | +|-----------------|----------| +| **DI Container** | Services, parameters, extensions | +| **Database** | Tables, columns, relationships | +| **Router** | Routes, URL matching, generation | +| **Tracy** | Exceptions, warnings, logs | + +MCP Inspector works with Claude Code, Cursor, VS Code with Continue, and any other tool that supports the MCP protocol. + +[Learn more about MCP Inspector |mcp-inspector] + + +Claude Code Plugin +------------------ + +For users of Claude Code, there's an additional plugin that gives Claude deep knowledge of Nette conventions. It includes 10 specialized "skills" that activate automatically: + +| Skill | What It Covers | +|-------|----------------| +| nette-architecture | Presenters, modules, directory structure | +| nette-database | Database Explorer, entities, queries | +| nette-forms | Controls, validation, rendering | +| latte-templates | Syntax, filters, security | +| + 6 more... | [See complete list |claude-code] | + +The plugin also automatically validates Latte templates and NEON files after every edit. + +[Learn more about Claude Code Plugin |claude-code] + + +Other AI Tools +-------------- + +MCP Inspector works with any MCP-compatible tool. Setup guides for additional tools are coming soon: + +- **Cursor** – Popular AI-first code editor +- **VS Code + Continue** – Open-source AI coding assistant +- **Gemini CLI** – Google's command-line AI tool + + +Getting Started +=============== + +Ready to try vibe coding with Nette? The setup takes about 10 minutes: + +1. **Choose your AI tool** – We recommend Claude Code for the best Nette experience +2. **Install MCP Inspector** – The core that gives AI access to your application +3. **Start coding** – Describe what you want and let AI help + +[Complete setup guide |getting-started] + diff --git a/ai/en/mcp-inspector.texy b/ai/en/mcp-inspector.texy new file mode 100644 index 0000000000..5965a94677 --- /dev/null +++ b/ai/en/mcp-inspector.texy @@ -0,0 +1,448 @@ +MCP Inspector +************* + +
+ +MCP Inspector is the bridge between **any AI tool** and your Nette application. It allows AI assistants to look directly at your running app – to see what services you have registered, what your database schema looks like, which routes are defined, and what errors have occurred. + +This is what makes the difference between AI that guesses and AI that knows. + +
+ + +Supported AI Tools +================== + +MCP Inspector works with any tool that supports the **Model Context Protocol (MCP)**: + +- **[Claude Code |claude-code]** – Full support with dedicated Nette plugin +- **Cursor** – Configure via `.cursor/mcp.json` +- **VS Code + Continue** – Configure via Continue settings +- **Any MCP-compatible tool** – See [manual configuration |#manual-mcp-configuration] + + +Why MCP Matters +=============== + +Imagine you ask your AI: "Generate an entity for the product table." + +Without MCP Inspector, the AI has to guess what columns your table has. It might assume common patterns like `id`, `name`, `price` – but what if your table has different columns? What if `price` is called `unit_price`? What if you have a `currency_id` foreign key? + +With MCP Inspector, the AI doesn't guess. It calls `db_get_columns("product")` and sees your actual schema: + +The result is code that actually works with your database, not code you have to fix. + + +Installation +============ + +If you're using the [Nette plugin for Claude Code |claude-code], installation is simple: + +```shell +/install-mcp-inspector +``` + +This command adds `nette/mcp-inspector` to your project and configures everything automatically. + +For other AI tools or manual installation: + +```shell +composer require nette/mcp-inspector +``` + +Then configure your AI tool to use the MCP server – see [manual configuration |#manual-mcp-configuration] below. + +**Important:** After installation, restart your AI tool. The MCP server only connects when the tool starts. + + +How It Works +============ + +MCP Inspector runs as a background process that your AI tool can communicate with. When AI needs information about your application, it sends a request to MCP Inspector, which: + +1. Loads your application's DI container (using `App\Bootstrap`) +2. Executes the requested query (get services, read database schema, etc.) +3. Returns the result to the AI + +All operations are **read-only**. MCP Inspector can't modify your database, change configuration, or execute commands. + + +DI Container Tools +================== + +These tools let AI explore your service definitions. + + +di_get_services +--------------- + +Lists all registered services. You can filter by name or type. + +When AI asks "What mail services do I have?", it calls: + +``` +di_get_services("mail") +``` + +And gets a list like: + +``` +- mail.mailer (Nette\Mail\Mailer) +- App\Model\QueueMailer +- App\Core\SmtpTransport +``` + + +di_get_service +-------------- + +Gets detailed information about a specific service – how it's created, what setup methods are called, what tags it has. + + +di_get_parameters +----------------- + +Reads configuration parameters. Want to know what your database settings are? + +``` +di_get_parameters("database") +``` + +Note: Sensitive values (passwords, tokens, API keys) are automatically masked. + + +di_find_by_tag +-------------- + +Finds services with a specific tag. Useful for discovering CLI commands: + +``` +di_find_by_tag("console.command") +``` + + +di_find_by_type +--------------- + +Finds services implementing a specific interface: + +``` +di_find_by_type("Nette\\Security\\Authenticator") +``` + + +di_get_extensions +----------------- + +Lists all registered DI extensions with their configuration. + + +Database Tools +============== + +These tools give AI visibility into your database structure. + + +db_get_tables +------------- + +Lists all tables in your database. + + +db_get_columns +-------------- + +Gets detailed column information for a table – types, whether they're nullable, default values, and foreign key relationships. + +``` +db_get_columns("order") +``` + +Returns something like: + +``` +- id: int (PRIMARY KEY) +- customer_id: int (FK → customer.id) +- status: varchar(20) +- total: decimal(10,2) +- created_at: datetime +``` + + +db_get_relationships +-------------------- + +Shows all foreign key relationships in your database – which tables reference which other tables. + + +db_get_indexes +-------------- + +Lists indexes for a specific table. + + +db_explain_query +---------------- + +Runs `EXPLAIN` on a SELECT query to analyze its performance. AI can use this to suggest query optimizations. + + +db_generate_entity +------------------ + +The most useful tool for quick development. Given a table name, it generates a complete PHP entity class with proper type hints: + +``` +db_generate_entity("product") +``` + +Generates: + +```php +/** + * @property-read int $id + * @property-read string $name + * @property-read float $unit_price + * @property-read ?CategoryRow $category + * @property-read DateTimeImmutable $created_at + */ +final class ProductRow extends Table\ActiveRow +{ +} +``` + + +Router Tools +============ + +These tools help AI understand your URL structure. + + +router_get_routes +----------------- + +Lists all registered routes with their masks and default values. + + +router_match_url +---------------- + +Given a URL, finds which presenter and action handles it: + +``` +router_match_url("/admin/products/edit/5") +``` + +Returns: + +``` +Presenter: Admin:Product +Action: edit +Parameters: id=5 +``` + + +router_generate_url +------------------- + +Generates a URL for a given presenter and action: + +``` +router_generate_url("Admin:Product:edit", {"id": 5}) +``` + + +Tracy Tools +=========== + +These tools let AI see error logs and help with debugging. They're incredibly useful when something goes wrong – instead of you describing the error, AI can read it directly. + + +tracy_get_last_exception +------------------------ + +Gets the most recent exception from Tracy's log, including the full stack trace. When something breaks, this is the first thing AI checks. + +``` +tracy_get_last_exception() +``` + +Returns the exception class, message, file, line number, and complete stack trace. AI can analyze this to identify the root cause and suggest a fix. + +Example response: +``` +Exception: Nette\Database\UniqueConstraintViolationException +Message: Duplicate entry 'john@example.com' for key 'email' +File: /app/Model/UserService.php:45 +Stack trace: + #0 /app/Presentation/Admin/UserPresenter.php:32 + #1 /vendor/nette/application/src/... +``` + + +tracy_get_exceptions +-------------------- + +Lists recent exception files from Tracy's log directory. Useful for finding patterns or recurring issues. + +``` +tracy_get_exceptions(5) +``` + +Returns the 5 most recent exception files with timestamps. You can then use `tracy_get_exception_detail` to examine any of them. + + +tracy_get_exception_detail +-------------------------- + +Gets the complete details of a specific exception file. Use this when you want to examine an older exception, not just the latest one. + +``` +tracy_get_exception_detail("exception-2024-01-15-143022-abc123.html") +``` + + +tracy_get_warnings +------------------ + +Shows recent PHP warnings and notices from Tracy's log. These often indicate problems that don't crash the application but should be fixed. + +``` +tracy_get_warnings(10) +``` + +Common warnings AI can help fix: +- Undefined array key +- Deprecated function calls +- Type mismatch warnings + + +tracy_get_log +------------- + +Reads entries from any Tracy log level. Tracy supports multiple log files: `error.log`, `warning.log`, `info.log`, and custom levels. + +``` +tracy_get_log("error", 20) +``` + +This reads the last 20 entries from the error log. Useful for seeing a history of issues, not just the most recent one. + + +Creating Custom Tools +===================== + +You can extend MCP Inspector with your own tools. This is useful if you have application-specific data that AI should be able to query. + +Create a class implementing the `Toolkit` interface: + +```php +use Mcp\Capability\Attribute\McpTool; +use Nette\McpInspector\Toolkit; +use Nette\McpInspector\Bridge\BootstrapBridge; + +class OrderToolkit implements Toolkit +{ + public function __construct( + private BootstrapBridge $bridge, + ) {} + + /** + * Get pending orders count and total value. + */ + #[McpTool(name: 'orders_get_pending_summary')] + public function getPendingSummary(): array + { + $db = $this->bridge->getContainer() + ->getByType(Nette\Database\Explorer::class); + + $result = $db->table('order') + ->where('status', 'pending') + ->select('COUNT(*) AS count, SUM(total) AS total') + ->fetch(); + + return [ + 'count' => $result->count, + 'total' => $result->total, + ]; + } +} +``` + +Register it in `mcp-config.neon`: + +```neon +toolkits: + - App\Mcp\OrderToolkit +``` + +Now AI can call `orders_get_pending_summary()` to get real-time order statistics. + + +Configuration +============= + +MCP Inspector works out of the box with the default Nette project structure. If your setup is different, create `mcp-config.neon` in your project root: + +```neon +# Path to Bootstrap file (if not in default location) +bootstrap: src/Bootstrap.php + +# Bootstrap class name (if different from default) +bootstrapClass: MyApp\Bootstrap + +# Additional custom toolkits +toolkits: + - App\Mcp\OrderToolkit + - App\Mcp\CustomerToolkit +``` + + +Manual MCP Configuration +------------------------ + +For AI tools other than Claude Code (which configures automatically via the plugin), add MCP Inspector to your tool's configuration: + +**For most MCP-compatible tools**, create `.mcp.json` in your project root: + +```json +{ + "mcpServers": { + "nette-inspector": { + "command": "php", + "args": ["vendor/bin/mcp-inspector"] + } + } +} +``` + +**For Cursor**, add to `.cursor/mcp.json`: + +```json +{ + "mcpServers": { + "nette-inspector": { + "command": "php", + "args": ["vendor/bin/mcp-inspector"] + } + } +} +``` + +Consult your AI tool's documentation for the exact configuration location. + + +Security Considerations +======================= + +MCP Inspector is designed for development environments. Here's what you should know: + +**Read-only by design** – All tools only read data, never modify it. + +**Database protection** – The `db_explain_query` tool only accepts SELECT, SHOW, DESCRIBE, and EXPLAIN queries. INSERT, UPDATE, DELETE, and other modifying queries are rejected. + +**Sensitive data masking** – Configuration values containing words like "password", "secret", "token", or "apikey" are automatically masked with `***MASKED***`. + +**Do not expose in production** – MCP Inspector should only run on development machines. It provides detailed information about your application internals that you don't want exposed publicly. + +{{composer: nette/mcp-inspector}} diff --git a/ai/en/tips.texy b/ai/en/tips.texy new file mode 100644 index 0000000000..586f558519 --- /dev/null +++ b/ai/en/tips.texy @@ -0,0 +1,296 @@ +Tips for AI-Assisted Development +******************************** + +
+ +AI is a powerful tool, but like any tool, you get better results when you know how to use it well. This page collects practical advice from real-world experience with AI-assisted Nette development. + +- How to write prompts that get better results +- Making the most of MCP Inspector +- Proven workflows for common tasks +- Mistakes to avoid + +
+ + +Writing Better Prompts +====================== + + +The Art of Being Specific +------------------------- + +The single biggest improvement you can make is being specific. Compare these two prompts: + +**Vague prompt:** + +``` +Create a form +``` + +This gives the AI almost no context. What form? What fields? What validation? The AI has to make assumptions, and those assumptions might not match what you need. + +**Specific prompt:** + +``` +Create a ProductForm with: +- name: text field, required, max 100 characters +- price: float field, required, must be positive +- description: textarea, optional +- category: select from CategoryRow entities + +Use Bootstrap 5 rendering. The form should work for both creating new products and editing existing ones. +``` + +Now the AI knows exactly what you need and can generate code that works on the first try. + + +Point to Existing Patterns +-------------------------- + +Your codebase already has patterns. Instead of explaining them, point the AI to examples: + +``` +Create an OrderPresenter. Follow the same patterns as ProductPresenter – +same structure, same way of handling forms, same template organization. +``` + +The AI will read ProductPresenter and replicate the patterns you're already using. + + +Let MCP Do the Heavy Lifting +---------------------------- + +If you have MCP Inspector installed (and you should!), don't explain your application – let the AI discover it: + +**Instead of:** + +``` +My product table has columns: id (int), name (varchar), price (decimal), +category_id (int, foreign key to category), created_at (datetime)... +``` + +**Just say:** + +``` +Generate an entity for the product table. +``` + +The AI will call `db_get_columns("product")` and see the actual schema. The generated entity will match your real database, including any columns you might have forgotten to mention. + + +Give Context About Your Goals +----------------------------- + +AI can't read your mind. If there's a reason behind your request, share it: + +``` +I need to optimize the product listing page. It's currently loading +all products at once, which is slow when there are thousands of items. +The page needs to support filtering by category and sorting by price or name. +``` + +This helps the AI suggest an appropriate solution (pagination, lazy loading, caching) rather than just blindly implementing what you asked for. + + +Working with MCP Inspector +========================== + +MCP Inspector is most powerful when you use it strategically. + + +Explore Before You Build +------------------------ + +Starting a new feature? Let the AI understand the context first: + +``` +I'm going to add order tracking. Before we start: +1. What services do I have related to orders? +2. What does my order table look like? +3. What routes handle order-related pages? +``` + +This gives the AI context about your existing code, so the new feature fits naturally. + + +Debug Smarter +------------- + +When something goes wrong, don't describe the error – let the AI see it: + +``` +Something broke. Check the Tracy log for the last exception +and tell me what went wrong. +``` + +The AI will call `tracy_get_last_exception()`, read the stack trace, and can often identify the problem faster than you could explain it. + + +Verify Before You Create +------------------------ + +Before adding new routes or links, verify what exists: + +``` +What presenter handles /admin/products/edit? I want to make sure +I'm not creating something that conflicts. +``` + + +Common Workflows +================ + +Here are proven approaches for common tasks. + + +Creating a Complete CRUD +------------------------ + +Don't ask for one piece at a time. Give the AI the full picture: + +``` +Create a complete CRUD for managing products: + +1. ProductPresenter with actions: list, add, edit, delete +2. ProductForm as a component (works for both add and edit) +3. Latte templates for all actions +4. Route suggestions + +Use the actual product table schema. Follow the patterns +in CategoryPresenter if it exists. +``` + + +Adding a New Feature +-------------------- + +Break it down into phases that build on each other: + +``` +I need to add customer reviews to products. + +Phase 1 - Data layer: +- Look at the product table +- Suggest the review table schema +- Create ReviewRow entity + +Phase 2 - Business logic: +- Create ReviewService for CRUD operations +- Add methods to get reviews for a product + +Phase 3 - UI: +- Add review display to ProductPresenter:detail +- Create ReviewForm for submitting reviews +``` + + +Refactoring Existing Code +------------------------- + +Let the AI understand before it changes: + +``` +Analyze the OrderService class. What does each method do? +Are there any code smells or improvements you'd suggest? +``` + +Then: + +``` +The calculateTotal method is doing too much. Split it into +smaller methods while keeping the same public interface. +``` + + +Mistakes to Avoid +================= + + +Not Reviewing Generated Code +---------------------------- + +AI generates code quickly, but that doesn't mean every line is perfect. Always review: + +- **Database queries** – Are they efficient? Do they need indexes? +- **Security** – Is input validated? Are there authorization checks? +- **Edge cases** – What happens with empty data? Null values? + +AI is very good, but it's still an assistant. You're the developer responsible for the final code. + + +Ignoring Validation Feedback +---------------------------- + +If you're using the [Claude Code plugin |claude-code], it validates your Latte templates and NEON files automatically. When it reports an error, the AI knows about it. Instead of manually fixing the error, just say: + +``` +Fix the error you just created. +``` + +The AI will read the validation output and correct the mistake. + + +Forgetting Service Registration +------------------------------- + +When the AI creates a new service class, it sometimes forgets to register it in the DI container. If you get "Service not found" errors, ask: + +``` +What changes do I need in services.neon for the new OrderExportService? +``` + + +Asking for Too Much at Once +--------------------------- + +While AI can handle complex tasks, sometimes it helps to break them down: + +**Too ambitious:** + +``` +Build me a complete e-commerce system with product catalog, +shopping cart, checkout, payments, order tracking, and admin panel. +``` + +**Better approach:** + +``` +Let's build an e-commerce system step by step. Start with the product +catalog – I need to list, view, and admin products. +``` + + +When AI Excels (and When It Doesn't) +==================================== + + +AI is Great For +--------------- + +- **Boilerplate code** – Presenters, forms, entities, basic templates +- **Following patterns** – "Do it like X but for Y" +- **Understanding code** – "What does this method do?" +- **Generating tests** – Given implementation, create tests +- **Refactoring** – Improving code structure while keeping behavior + + +Consider Manual Coding For +-------------------------- + +- **Complex business logic** – Domain rules that require careful thinking +- **Performance-critical code** – Algorithms that need optimization +- **Security-sensitive code** – Authentication, authorization, encryption +- **Novel solutions** – Things that don't follow existing patterns + +AI is a multiplier, not a replacement. It makes good developers faster, but it still needs a good developer guiding it. + + +Final Thoughts +============== + +The best way to learn AI-assisted development is to practice. Start with simple tasks, pay attention to what works, and gradually take on more complex projects. + +And remember: the AI is your assistant. You're still the developer. You make the decisions, you review the code, and you're responsible for the quality of the final product. + +Happy coding! diff --git a/ai/meta.json b/ai/meta.json new file mode 100644 index 0000000000..0967ef424b --- /dev/null +++ b/ai/meta.json @@ -0,0 +1 @@ +{} diff --git a/application/bg/@meta.texy b/application/bg/@meta.texy new file mode 100644 index 0000000000..57804a1127 --- /dev/null +++ b/application/bg/@meta.texy @@ -0,0 +1 @@ +{{sitename: Документация на Nette}} diff --git a/application/bg/routing.texy b/application/bg/routing.texy index f6d0f09e15..d3a66e32fa 100644 --- a/application/bg/routing.texy +++ b/application/bg/routing.texy @@ -314,7 +314,7 @@ use Nette\Routing\Route; $router->addRoute('/', [ 'presenter' => 'Home', 'action' => 'default', - null => [ + '' => [ Route::FilterIn => function (array $params): array { /* ... */ }, Route::FilterOut => function (array $params): array { /* ... */ }, ], diff --git a/application/cs/@meta.texy b/application/cs/@meta.texy new file mode 100644 index 0000000000..462d9add80 --- /dev/null +++ b/application/cs/@meta.texy @@ -0,0 +1 @@ +{{sitename: Nette Dokumentace}} diff --git a/application/cs/ajax.texy b/application/cs/ajax.texy index fd274408d1..fe7772083f 100644 --- a/application/cs/ajax.texy +++ b/application/cs/ajax.texy @@ -247,3 +247,9 @@ public function handleFoo(int $bar): void { } ``` + + +Další četba +=========== + +- [Dynamické snippety |best-practices:dynamic-snippets] diff --git a/application/cs/components.texy b/application/cs/components.texy index 43a7f0f72b..7d433ab890 100644 --- a/application/cs/components.texy +++ b/application/cs/components.texy @@ -422,10 +422,10 @@ Nette\ComponentModel\Component { IComponent } ``` -Životní cyklus componenty +Životní cyklus komponenty ------------------------- -[* lifecycle-component.svg *] *** *Životní cyklus componenty* .<> +[* lifecycle-component.svg *] *** *Životní cyklus komponenty* .<> Validace persistentních parametrů diff --git a/application/cs/creating-links.texy b/application/cs/creating-links.texy index 0263cbbc4a..8658cb3646 100644 --- a/application/cs/creating-links.texy +++ b/application/cs/creating-links.texy @@ -12,7 +12,7 @@ Tvořit odkazy v Nette je jednoduché, jako ukazovat prstem. Stačí jen namíř -Díky [obousměrnému routování |routing] nebudete nikdy muset do šablon či kódu zapisovat navrdo URL adresy vaší aplikace, které se mohou později měnit, nebo je komplikovaně skládat. V odkazu stačí uvést presenter a akci, předat případné parametry a framework už URL vygeneruje sám. Vlastně je to velice podobné, jako když voláte funkci. To se vám bude líbit. +Díky [obousměrnému routování |routing] nebudete nikdy muset do šablon či kódu zapisovat natvrdo URL adresy vaší aplikace, které se mohou později měnit, nebo je komplikovaně skládat. V odkazu stačí uvést presenter a akci, předat případné parametry a framework už URL vygeneruje sám. Vlastně je to velice podobné, jako když voláte funkci. To se vám bude líbit. V šabloně presenteru @@ -130,6 +130,8 @@ Odkazy generované pomocí `link()` nebo `n:href` jsou vždy absolutní cesty (t Pro vygenerování absolutní URL přidejte na začátek dvě lomítka (např. `n:href="//Home:"`). Nebo lze přepnout presenter, aby generoval jen absolutní odkazy nastavením `$this->absoluteUrls = true`. +V šabloně lze také použít filtr `|absoluteUrl`, který relativní cestu převede na absolutní. + Odkaz na aktuální stránku ========================= @@ -179,6 +181,21 @@ Pro zjištění, zda jsme v určitém modulu nebo jeho submodulu, použijeme met ``` +Změna základu pro odkazy .{data-version:v3.2.7} +=============================================== + +Ve výchozím stavu se relativní odkazy odvíjejí od aktuálního presenteru. To lze změnit pomocí `{linkBase}`: + +```latte +{linkBase Admin:Dashboard} +detail produktu +``` + +Odkaz povede na `Admin:Dashboard:Product:show`. Ovlivněny jsou pouze relativní odkazy - absolutní odkazy začínající dvojtečkou a odkazy na aktuální presenter (`this`, `show`) zůstávají nezměněny. + +`{linkBase}` platí pro celou šablonu a je užitečné zejména v šablonách layoutu, kde zajistí konzistentní odkazy nezávisle na volajícím presenteru. + + Odkazy na signál ================ diff --git a/application/cs/presenters.texy b/application/cs/presenters.texy index 368fc7ceda..04cd942e32 100644 --- a/application/cs/presenters.texy +++ b/application/cs/presenters.texy @@ -122,6 +122,8 @@ Kdykoliv během životního cyklu můžeme některou z následujících metod od - `sendResponse($response)` presenter ukončí a odešle [vlastní odpověď |#Odpovědi] - `terminate()` presenter ukončí bez odpovědi +Každá z těchto metod okamžitě ukončí činnost presenteru vyhozením tzv. tiché ukončovací výjimky `Nette\Application\AbortException`. + Pokud žádnou z těchto metod nezavoláte, presenter automaticky přistoupí k vykreslí šablony. Proč? Protože v 99 % případů chceme vykreslit šablonu, tudíž presenter tohle chování bere jako výchozí a chce nám ulehčit práci. @@ -491,6 +493,14 @@ class MyPresenter extends Nette\Application\UI\Presenter Je důležité zdůraznit, že pokud povolíte metodu `OPTIONS`, musíte ji následně také patřičně obsloužit v rámci svého presenteru. Metoda je často používána jako tzv. preflight request, který prohlížeč automaticky odesílá před skutečným požadavkem, když je potřeba zjistit, zda je požadavek povolený z hlediska CORS (Cross-Origin Resource Sharing) politiky. Pokud metodu povolíte, ale neimplementujete správnou odpověď, může to vést k nekonzistencím a potenciálním bezpečnostním problémům. +Označení zastaralých akcí .{data-version:3.2.3} +----------------------------------------------- + +Atribut `#[Deprecated]` slouží k označení akcí, signálů nebo celých presenterů, které jsou zastaralé a měly by být v budoucnu odstraněny. Při generování odkazů na takto označené části aplikace Nette vyhodí varování, které vývojáře upozorní. + +Atribut lze aplikovat jak na celou třídu presenteru, tak na jednotlivé metody `action()`, `render()` a `handle()`. + + Další četba =========== diff --git a/application/cs/routing.texy b/application/cs/routing.texy index 826bed4363..3a2e753731 100644 --- a/application/cs/routing.texy +++ b/application/cs/routing.texy @@ -306,7 +306,7 @@ Parametry `presenter`, `action` a `module` už mají předdefinované filtry, kt Obecné filtry ------------- -Vedle filtrů určených pro konkrétní parametry můžeme definovat též obecné filtry, které obdrží asociativní pole všech parametrů, které mohou jakkoliv modifikovat a poté je vrátí. Obecné filtry definujeme pod klíčem `null`. +Vedle filtrů určených pro konkrétní parametry můžeme definovat též obecné filtry, které obdrží asociativní pole všech parametrů, které mohou jakkoliv modifikovat a poté je vrátí. Obecné filtry definujeme pod prázdným klíčem. ```php use Nette\Routing\Route; @@ -314,7 +314,7 @@ use Nette\Routing\Route; $router->addRoute('/', [ 'presenter' => 'Home', 'action' => 'default', - null => [ + '' => [ Route::FilterIn => function (array $params): array { /* ... */ }, Route::FilterOut => function (array $params): array { /* ... */ }, ], diff --git a/application/cs/templates.texy b/application/cs/templates.texy index 4ded503e34..5e4452a586 100644 --- a/application/cs/templates.texy +++ b/application/cs/templates.texy @@ -114,15 +114,48 @@ Soubory, kde se dohledávají šablony layoutu, lze změnit překrytím metody [ Proměnné v šabloně ------------------ -Proměnné do šablony předáváme tak, že je zapíšeme do `$this->template` a potom je máme k dispozici v šabloně jako lokální proměnné: +Proměnné do šablony předáváme zápisem do `$this->template`. V šabloně jsou pak dostupné jako lokální proměnné: ```php $this->template->article = $this->articles->getById($id); ``` -Takto jednoduše můžeme do šablon předat jakékoliv proměnné. Při vývoji robustních aplikací ale bývá užitečnější se omezit. Například tak, že explicitně nadefinujeme výčet proměnných, které šablona očekává, a jejich typů. Díky tomu nám bude moci PHP kontrolovat typy, IDE správně našeptávat a statická analýza odhalovat chyby. +Pokud chcete, aby se hodnota určité property automaticky předala do šablony jako proměnná, označte ji atributem `#[TemplateVariable]` a viditelností public nebo protected: .{data-version:3.2.9} -A jak takový výčet nadefinujeme? Jednoduše v podobě třídy a její properties. Pojmenujeme ji podobně jako presenter, jen s `Template` na konci: +```php +use Nette\Application\Attributes\TemplateVariable; + +class ArticlePresenter extends Nette\Application\UI\Presenter +{ + #[TemplateVariable] + public string $siteName = 'Můj blog'; +} +``` + +Pokud do šablony vložíte proměnnou se stejným názvem, `#[TemplateVariable]` ji nepřepíše. + + +Výchozí proměnné +---------------- + +Presentery a komponenty předávají do šablon několik užitečných proměnných automaticky: + +- `$basePath` je absolutní URL cesta ke kořenovému adresáři (např. `/eshop`) +- `$baseUrl` je absolutní URL ke kořenovému adresáři (např. `http://localhost/eshop`) +- `$user` je objekt [reprezentující uživatele |security:authentication] +- `$presenter` je aktuální presenter +- `$control` je aktuální komponenta nebo presenter +- `$flashes` pole [zpráv |presenters#Flash zprávy] zaslaných funkcí `flashMessage()` + +Pokud používáte vlastní třídu šablony, tyto proměnné se předají, pokud pro ně vytvoříte property. + + +Typově bezpečné šablony +----------------------- + +Při vývoji robustních aplikací je užitečné explicitně nadefinovat, jaké proměnné šablona očekává a jakého jsou typu. Získáte tak typovou kontrolu v PHP, chytré našeptávání v IDE a schopnost statické analýzy odhalovat chyby. + +Jak takový výčet nadefinovat? Jednoduše v podobě třídy s properties reprezentujícími proměnné šablony. Pojmenujeme ji podobně jako presenter, jen s `Template` na konci: ```php /** @@ -141,22 +174,22 @@ class ArticleTemplate extends Nette\Bridges\ApplicationLatte\Template } ``` -Objekt `$this->template` v presenteru bude nyní instancí třídy `ArticleTemplate`. Takže PHP bude při zápisu kontrolovat deklarované typy. A počínaje verzí PHP 8.2 upozorní i na zápis do neexistující proměnné, v předchozích verzích lze téhož dosáhnout použitím traity [Nette\SmartObject |utils:smartobject]. +Objekt `$this->template` v presenteru bude nyní instancí třídy `ArticleTemplate`. PHP tak bude při zápisu kontrolovat deklarované typy. -Anotace `@property-read` je určená pro IDE a statickou analýzu, díky ní bude fungovat našeptávání, viz "PhpStorm and code completion for $this⁠-⁠>⁠template":https://blog.nette.org/en/phpstorm-and-code-completion-for-this-template. +Anotace `@property-read` slouží pro IDE a statickou analýzu, díky ní bude fungovat našeptávání, viz "PhpStorm and code completion for $this⁠-⁠>⁠template":https://blog.nette.org/en/phpstorm-and-code-completion-for-this-template. [* phpstorm-completion.webp *] -Luxusu našeptávání si můžete dopřát i v šablonách, stačí do PhpStorm nainstalovat plugin pro Latte a uvést na začátek šablony název třídy, více v článku "Latte: jak na typový systém":https://blog.nette.org/cs/latte-jak-na-typovy-system: +Našeptávání můžete využít i přímo v šablonách. Stačí do PhpStorm nainstalovat plugin pro Latte a uvést na začátek šablony název třídy parametrů šablony, více v článku "Latte: jak na typový systém":https://blog.nette.org/cs/latte-jak-na-typovy-system: ```latte {templateType App\Presentation\Article\ArticleTemplate} ... ``` -Takto fungují i šablony v komponentách, stačí jen dodržet jmennou konvenci a pro komponentu např. `FifteenControl` vytvořit třídu šablony `FifteenTemplate`. +Totéž platí i pro komponenty. Stačí dodržet jmennou konvenci a pro komponentu např. `FifteenControl` vytvořit třídu parametrů `FifteenTemplate`. -Pokud potřebujete vytvořit `$template` jako instanci jiné třídy, využijte metodu `createTemplate()`: +Pokud potřebujete použít jinou třídu parametrů, využijte metodu `createTemplate()`: ```php public function renderDefault(): void @@ -169,21 +202,6 @@ public function renderDefault(): void ``` -Výchozí proměnné ----------------- - -Presentery a komponenty předávají do šablon několik užitečných proměnných automaticky: - -- `$basePath` je absolutní URL cesta ke kořenovému adresáři (např. `/eshop`) -- `$baseUrl` je absolutní URL ke kořenovému adresáři (např. `http://localhost/eshop`) -- `$user` je objekt [reprezentující uživatele |security:authentication] -- `$presenter` je aktuální presenter -- `$control` je aktuální komponenta nebo presenter -- `$flashes` pole [zpráv |presenters#Flash zprávy] zaslaných funkcí `flashMessage()` - -Pokud používáte vlastní třídu šablony, tyto proměnné se předají, pokud pro ně vytvoříte property. - - Vytváření odkazů ---------------- @@ -205,21 +223,67 @@ Více informací najdete v kapitole [Vytváření odkazů URL|creating-links]. Vlastní filtry, značky apod. ---------------------------- -Šablonovací systém Latte lze rozšířit o vlastní filtry, funkce, značky apod. Lze tak učinit přímo v metodě `render` nebo `beforeRender()`: +Šablonovací systém Latte lze rozšířit o vlastní filtry, funkce, značky a další prvky. K dispozici jsou tři způsoby, jak to udělat, od nejrychlejších ad-hoc řešení až po architektonický přístup pro celou aplikaci. + +**Ad-hoc v metodách presenteru** + +Nejrychlejší způsob je přidat filtr nebo funkci přímo v kódu presenteru či komponenty. V presenteru je k tomu vhodná metoda `beforeRender()` nebo `render()`: ```php -public function beforeRender(): void +protected function beforeRender(): void { // přidání filtru - $this->template->addFilter('foo', /* ... */); + $this->template->addFilter('money', fn($val) => round($val) . ' Kč'); + + // přidání funkce + $this->template->addFunction('isWeekend', fn($date) => $date->format('N') >= 6); +} +``` + +V šabloně pak: - // nebo konfigurujeme přímo objekt Latte\Engine +```latte +

Cena: {$price|money}

+ +{if isWeekend($now)} ... {/if} +``` + +Pro složitější logiku můžete konfigurovat přímo objekt `Latte\Engine`: + +```php +protected function beforeRender(): void +{ $latte = $this->template->getLatte(); - $latte->addFilterLoader(/* ... */); + $latte->setFeature(Latte\Feature::MigrationWarnings); +} +``` + +**Pomocí atributů** + +Elegantní způsob je definovat filtry a funkce jako metody přímo ve [třídě parametrů šablony|#Typově bezpečné šablony] presenteru nebo komponenty a označit je atributy: + +```php +class ArticleTemplate extends Nette\Bridges\ApplicationLatte\Template +{ + #[Latte\Attributes\TemplateFilter] + public function money(float $val): string + { + return round($val) . ' Kč'; + } + + #[Latte\Attributes\TemplateFunction] + public function isWeekend(DateTimeInterface $date): bool + { + return $date->format('N') >= 6; + } } ``` -Latte ve verzi 3 nabízí pokročilejší způsob a to vytvoření si [extension |latte:extending-latte#Latte Extension] pro každý webový projekt. Kusý příklad takové třídy: +Latte automaticky rozpozná a zaregistruje metody označené těmito atributy. Název filtru nebo funkce v šabloně odpovídá názvu metody. Tyto metody nesmí být privátní. + +**Globálně pomocí Extension** + +Předchozí způsoby jsou vhodné pro filtry a funkce, které potřebujete jen v konkrétním presenteru nebo komponentě, nikoliv v celé aplikaci. Pro celou aplikaci je nejvhodnější vytvořit si [extension |latte:extending-latte#Latte Extension]. Jde o třídu, která centralizuje všechna rozšíření Latte pro celý projekt. Kusý příklad: ```php namespace App\Presentation\Accessory; @@ -251,11 +315,16 @@ final class LatteExtension extends Latte\Extension ]; } + private function filterTimeAgoInWords(DateTimeInterface $time): string + { + // ... + } + // ... } ``` -Zaregistrujeme ji pomocí [konfigurace |configuration#Šablony Latte]: +Extension zaregistrujeme pomocí [konfigurace |configuration#Šablony Latte]: ```neon latte: @@ -263,6 +332,8 @@ latte: - App\Presentation\Accessory\LatteExtension ``` +Výhodou extension je, že lze využít dependency injection, mít přístup k modelové vrstvě aplikace a všechna rozšíření mít přehledně na jednom místě. Extension umožnuje definovat i vlastní značky, providery, průchody pro Latte kompilátor a další. + Překládání ---------- diff --git a/application/de/@meta.texy b/application/de/@meta.texy new file mode 100644 index 0000000000..b3b806b2ca --- /dev/null +++ b/application/de/@meta.texy @@ -0,0 +1 @@ +{{sitename: Nette Dokumentation}} diff --git a/application/de/routing.texy b/application/de/routing.texy index 251247119d..ff2f7378e0 100644 --- a/application/de/routing.texy +++ b/application/de/routing.texy @@ -314,7 +314,7 @@ use Nette\Routing\Route; $router->addRoute('/', [ 'presenter' => 'Home', 'action' => 'default', - null => [ + '' => [ Route::FilterIn => function (array $params): array { /* ... */ }, Route::FilterOut => function (array $params): array { /* ... */ }, ], diff --git a/application/el/@meta.texy b/application/el/@meta.texy new file mode 100644 index 0000000000..88e29852c7 --- /dev/null +++ b/application/el/@meta.texy @@ -0,0 +1 @@ +{{sitename: Nette Τεκμηρίωση}} diff --git a/application/el/routing.texy b/application/el/routing.texy index 4886294f8b..31800ef023 100644 --- a/application/el/routing.texy +++ b/application/el/routing.texy @@ -314,7 +314,7 @@ use Nette\Routing\Route; $router->addRoute('/', [ 'presenter' => 'Home', 'action' => 'default', - null => [ + '' => [ Route::FilterIn => function (array $params): array { /* ... */ }, Route::FilterOut => function (array $params): array { /* ... */ }, ], diff --git a/application/en/@meta.texy b/application/en/@meta.texy new file mode 100644 index 0000000000..42471908b0 --- /dev/null +++ b/application/en/@meta.texy @@ -0,0 +1 @@ +{{sitename: Nette Documentation}} diff --git a/application/en/ajax.texy b/application/en/ajax.texy index 21a4475c2a..b65ca6adce 100644 --- a/application/en/ajax.texy +++ b/application/en/ajax.texy @@ -247,3 +247,9 @@ public function handleFoo(int $bar): void { } ``` + + +Further Reading +=============== + +- [Dynamic Snippets |best-practices:dynamic-snippets] diff --git a/application/en/creating-links.texy b/application/en/creating-links.texy index 45ec9bd73e..f831b5e018 100644 --- a/application/en/creating-links.texy +++ b/application/en/creating-links.texy @@ -130,6 +130,8 @@ Links generated using `link()` or `n:href` are always absolute paths (i.e., they To generate an absolute URL, add two slashes at the beginning (e.g., `n:href="//Home:"`). Alternatively, you can switch the presenter to generate only absolute links by setting `$this->absoluteUrls = true`. +The `|absoluteUrl` filter can also be used in the template to convert a relative path to an absolute path. + Link to Current Page ==================== @@ -179,6 +181,21 @@ To determine if we are in a specific module or its submodule, use the `isModuleC ``` +Changing Link Base .{data-version:v3.2.7} +========================================= + +By default, relative links are derived from the current presenter. This can be changed using `{linkBase}`: + +```latte +{linkBase Admin:Dashboard} +product detail +``` + +The link will lead to `Admin:Dashboard:Product:show`. Only relative links are affected - absolute links starting with a colon and links to the current presenter (`this`, `show`) remain unchanged. + +`{linkBase}` applies to the entire template and is especially useful in layout templates, where it ensures consistent links regardless of the calling presenter. + + Links to Signal =============== diff --git a/application/en/presenters.texy b/application/en/presenters.texy index 3d36da3b2c..7658686bbf 100644 --- a/application/en/presenters.texy +++ b/application/en/presenters.texy @@ -122,6 +122,8 @@ At any point during the life cycle, we can use one of the following methods to s - `sendResponse($response)` terminates the presenter and sends a [custom response |#Responses] - `terminate()` terminates the presenter without a response +Each of these methods immediately terminates the presenter by throwing a silent termination exception `Nette\Application\AbortException`. + If you don't call any of these methods, the presenter automatically proceeds to render the template. Why? Because in 99% of cases, we want to render a template, so the presenter adopts this behavior as the default to simplify our work. @@ -491,6 +493,14 @@ class MyPresenter extends Nette\Application\UI\Presenter It's important to emphasize that if you enable the `OPTIONS` method, you must subsequently handle it appropriately within your presenter. This method is often used as a so-called preflight request, which the browser automatically sends before the actual request when it's necessary to determine if the request is permissible according to the CORS (Cross-Origin Resource Sharing) policy. If you enable the method but don't implement the correct response, it can lead to inconsistencies and potential security problems. +Marking Deprecated Actions .{data-version:3.2.3} +------------------------------------------------ + +The `#[Deprecated]` attribute marks actions, signals, or entire presenters as deprecated and scheduled for future removal. When generating links to deprecated parts of the application, Nette throws a warning to alert developers. + +You can apply the attribute to either the entire presenter class or to individual `action()`, `render()`, and `handle()` methods. + + Further Reading =============== diff --git a/application/en/routing.texy b/application/en/routing.texy index daa1c181d8..4b83f317f2 100644 --- a/application/en/routing.texy +++ b/application/en/routing.texy @@ -306,7 +306,7 @@ The parameters `presenter`, `action`, and `module` already have predefined filte General Filters --------------- -Besides filters intended for specific parameters, we can also define general filters that receive an associative array of all parameters, which they can modify in any way and then return. General filters are defined under the key `null`. +Besides filters intended for specific parameters, we can also define general filters that receive an associative array of all parameters, which they can modify in any way and then return. General filters are defined under the empty key. ```php use Nette\Routing\Route; @@ -314,7 +314,7 @@ use Nette\Routing\Route; $router->addRoute('/', [ 'presenter' => 'Home', 'action' => 'default', - null => [ + '' => [ Route::FilterIn => function (array $params): array { /* ... */ }, Route::FilterOut => function (array $params): array { /* ... */ }, ], diff --git a/application/en/templates.texy b/application/en/templates.texy index 2950a8f35c..c5de1f1484 100644 --- a/application/en/templates.texy +++ b/application/en/templates.texy @@ -111,18 +111,51 @@ Using `$this->setLayout(false)` or the `{layout none}` tag inside the template d The files where layout templates are looked up can be changed by overriding the [formatLayoutTemplateFiles() |api:Nette\Application\UI\Presenter::formatLayoutTemplateFiles()] method, which returns an array of possible file names. -Variables in the Template -------------------------- +Template Variables +------------------ -Variables are passed to the template by writing them to `$this->template`, and then they are available in the template as local variables: +Variables are passed to templates by writing them to `$this->template`. They then become available in the template as local variables: ```php $this->template->article = $this->articles->getById($id); ``` -This way, we can easily pass any variables to templates. However, when developing robust applications, it is often more useful to impose limitations. For example, by explicitly defining a list of variables that the template expects and their types. This allows PHP to perform type checking, the IDE to provide correct autocompletion, and static analysis to detect errors. +To automatically pass a property value to the template as a variable, mark it with the `#[TemplateVariable]` attribute and public or protected visibility: .{data-version:3.2.9} -And how do we define such a list? Simply in the form of a class and its properties. We name it similarly to the presenter, but with `Template` at the end: +```php +use Nette\Application\Attributes\TemplateVariable; + +class ArticlePresenter extends Nette\Application\UI\Presenter +{ + #[TemplateVariable] + public string $siteName = 'My blog'; +} +``` + +If you pass a variable with the same name to the template, `#[TemplateVariable]` won’t override it. + + +Default Variables +----------------- + +Presenters and components automatically pass several useful variables to templates: + +- `$basePath` is the absolute URL path to the root directory (e.g., `/eshop`) +- `$baseUrl` is the absolute URL to the root directory (e.g., `http://localhost/eshop`) +- `$user` is an object [representing the user |security:authentication] +- `$presenter` is the current presenter +- `$control` is the current component or presenter +- `$flashes` is an array of [messages |presenters#Flash Messages] sent by the `flashMessage()` function + +If you use a custom template class, these variables are passed if you create a property for them. + + +Type-Safe Templates +------------------- + +When developing robust applications, it's useful to explicitly define which variables the template expects and their types. This provides type checking in PHP, smart hints in your IDE, and enables static analysis to catch errors. + +How do you define such a list? Simply as a class with properties representing template variables. Name it similarly to the presenter, just with `Template` at the end: ```php /** @@ -141,22 +174,22 @@ class ArticleTemplate extends Nette\Bridges\ApplicationLatte\Template } ``` -The `$this->template` object in the presenter will now be an instance of the `ArticleTemplate` class. So PHP will check the declared types upon writing. And starting from PHP 8.2, it will also warn about writing to a non-existent variable; in previous versions, the same can be achieved using the [Nette\SmartObject |utils:smartobject] trait. +The `$this->template` object in the presenter will now be an instance of the `ArticleTemplate` class. PHP will thus check the declared types when writing. -The `@property-read` annotation is intended for IDEs and static analysis; thanks to it, autocompletion will work, see "PhpStorm and code completion for $this->template":https://blog.nette.org/en/phpstorm-and-code-completion-for-this-template. +The `@property-read` annotation is for the IDE and static analysis, enabling code completion, see "PhpStorm and code completion for $this⁠-⁠>⁠template":https://blog.nette.org/en/phpstorm-and-code-completion-for-this-template. [* phpstorm-completion.webp *] -You can enjoy the luxury of autocompletion in templates too; just install the Latte plugin for PhpStorm and specify the class name at the beginning of the template, more in the article "Latte: How to Use Type System":https://blog.nette.org/en/latte-how-to-use-type-system: +You can also use code completion directly in templates. Just install the Latte plugin for PhpStorm and specify the template parameter class name at the beginning of the template, more in the article "Latte: how to use the type system":https://blog.nette.org/en/latte-how-to-use-type-system: ```latte {templateType App\Presentation\Article\ArticleTemplate} ... ``` -This is also how templates work in components; just follow the naming convention and create a template class `FifteenTemplate` for a component like `FifteenControl`. +The same applies to components. Just follow the naming convention and create a parameter class `FifteenTemplate` for a component like `FifteenControl`. -If you need to create `$template` as an instance of another class, use the `createTemplate()` method: +If you need to use a different parameter class, use the `createTemplate()` method: ```php public function renderDefault(): void @@ -169,21 +202,6 @@ public function renderDefault(): void ``` -Default Variables ------------------ - -Presenters and components automatically pass several useful variables to templates: - -- `$basePath` is the absolute URL path to the root directory (e.g., `/eshop`) -- `$baseUrl` is the absolute URL to the root directory (e.g., `http://localhost/eshop`) -- `$user` is an object [representing the user |security:authentication] -- `$presenter` is the current presenter -- `$control` is the current component or presenter -- `$flashes` is an array of [messages |presenters#Flash Messages] sent by the `flashMessage()` function - -If you use a custom template class, these variables are passed if you create a property for them. - - Creating Links -------------- @@ -205,21 +223,67 @@ More information can be found in the chapter [Creating URL Links|creating-links] Custom Filters, Tags, etc. -------------------------- -The Latte templating system can be extended with custom filters, functions, tags, etc. This can be done directly in the `render` or `beforeRender()` method: +The Latte templating system can be extended with custom filters, functions, tags, and other elements. There are three approaches available, ranging from quick ad-hoc solutions to architectural patterns for entire applications. + +**Ad-hoc in Presenter Methods** + +The quickest approach is adding filters or functions directly in presenter or component code. In presenters, the `beforeRender()` or `render()` methods work well for this: ```php -public function beforeRender(): void +protected function beforeRender(): void { // adding a filter - $this->template->addFilter('foo', /* ... */); + $this->template->addFilter('money', fn($val) => '$' . number_format($val, 2)); + + // adding a function + $this->template->addFunction('isWeekend', fn($date) => $date->format('N') >= 6); +} +``` + +In the template: - // or configure the Latte\Engine object directly +```latte +

Price: {$price|money}

+ +{if isWeekend($now)} ... {/if} +``` + +For more complex logic, you can configure the `Latte\Engine` object directly: + +```php +protected function beforeRender(): void +{ $latte = $this->template->getLatte(); - $latte->addFilterLoader(/* ... */); + $latte->setFeature(Latte\Feature::MigrationWarnings); +} +``` + +**Using Attributes** + +A more elegant approach is defining filters and functions as methods directly in the presenter or component's [template parameter class|#Type-safe templates], marked with attributes: + +```php +class ArticleTemplate extends Nette\Bridges\ApplicationLatte\Template +{ + #[Latte\Attributes\TemplateFilter] + public function money(float $val): string + { + return '$' . number_format($val, 2); + } + + #[Latte\Attributes\TemplateFunction] + public function isWeekend(DateTimeInterface $date): bool + { + return $date->format('N') >= 6; + } } ``` -Latte version 3 offers a more advanced way by creating an [extension |latte:extending-latte#Latte Extension] for each web project. Here is a brief example of such a class: +Latte automatically discovers and registers methods marked with these attributes. The filter or function name in templates matches the method name. These methods must not be private. + +**Globally Using Extensions** + +The previous approaches suit filters and functions needed only in specific presenters or components, not application-wide. For the entire application, creating an [extension |latte:extending-latte#Latte Extension] works best. This class centralizes all Latte extensions for your project. A brief example: ```php namespace App\Presentation\Accessory; @@ -251,11 +315,16 @@ final class LatteExtension extends Latte\Extension ]; } + private function filterTimeAgoInWords(DateTimeInterface $time): string + { + // ... + } + // ... } ``` -We register it using [configuration |configuration#Latte Templates]: +Register the extension through [configuration |configuration#Latte Templates]: ```neon latte: @@ -263,6 +332,8 @@ latte: - App\Presentation\Accessory\LatteExtension ``` +Extensions offer several advantages: dependency injection support, access to your application's model layer, and centralized management of all extensions. They also support custom tags, providers, compiler passes, and more. + Translating ----------- diff --git a/application/es/@meta.texy b/application/es/@meta.texy new file mode 100644 index 0000000000..1670b124ad --- /dev/null +++ b/application/es/@meta.texy @@ -0,0 +1 @@ +{{sitename: Nette Documentación}} diff --git a/application/es/routing.texy b/application/es/routing.texy index 829edb3c7d..d906f83f48 100644 --- a/application/es/routing.texy +++ b/application/es/routing.texy @@ -314,7 +314,7 @@ use Nette\Routing\Route; $router->addRoute('/', [ 'presenter' => 'Home', 'action' => 'default', - null => [ + '' => [ Route::FilterIn => function (array $params): array { /* ... */ }, Route::FilterOut => function (array $params): array { /* ... */ }, ], diff --git a/application/fr/@meta.texy b/application/fr/@meta.texy new file mode 100644 index 0000000000..72ae4b8db8 --- /dev/null +++ b/application/fr/@meta.texy @@ -0,0 +1 @@ +{{sitename: Documentation Nette}} diff --git a/application/fr/routing.texy b/application/fr/routing.texy index 41a575cac4..66bfebc31b 100644 --- a/application/fr/routing.texy +++ b/application/fr/routing.texy @@ -314,7 +314,7 @@ use Nette\Routing\Route; $router->addRoute('/', [ 'presenter' => 'Home', 'action' => 'default', - null => [ + '' => [ Route::FilterIn => function (array $params): array { /* ... */ }, Route::FilterOut => function (array $params): array { /* ... */ }, ], diff --git a/application/hu/@meta.texy b/application/hu/@meta.texy new file mode 100644 index 0000000000..c172d1cda5 --- /dev/null +++ b/application/hu/@meta.texy @@ -0,0 +1 @@ +{{sitename: Nette dokumentáció}} diff --git a/application/hu/routing.texy b/application/hu/routing.texy index 0887f12764..4fb937eba5 100644 --- a/application/hu/routing.texy +++ b/application/hu/routing.texy @@ -314,7 +314,7 @@ use Nette\Routing\Route; $router->addRoute('/', [ 'presenter' => 'Home', 'action' => 'default', - null => [ + '' => [ Route::FilterIn => function (array $params): array { /* ... */ }, Route::FilterOut => function (array $params): array { /* ... */ }, ], diff --git a/application/it/@meta.texy b/application/it/@meta.texy new file mode 100644 index 0000000000..4647d0c8a2 --- /dev/null +++ b/application/it/@meta.texy @@ -0,0 +1 @@ +{{sitename: Documentazione Nette}} diff --git a/application/it/routing.texy b/application/it/routing.texy index c308d57f62..36b8f5968c 100644 --- a/application/it/routing.texy +++ b/application/it/routing.texy @@ -314,7 +314,7 @@ use Nette\Routing\Route; $router->addRoute('/', [ 'presenter' => 'Home', 'action' => 'default', - null => [ + '' => [ Route::FilterIn => function (array $params): array { /* ... */ }, Route::FilterOut => function (array $params): array { /* ... */ }, ], diff --git a/application/ja/@meta.texy b/application/ja/@meta.texy new file mode 100644 index 0000000000..d3c41dc3d7 --- /dev/null +++ b/application/ja/@meta.texy @@ -0,0 +1 @@ +{{sitename: Nette ドキュメンテーション}} diff --git a/application/ja/routing.texy b/application/ja/routing.texy index d3c524f7ab..4dd36be16c 100644 --- a/application/ja/routing.texy +++ b/application/ja/routing.texy @@ -314,7 +314,7 @@ use Nette\Routing\Route; $router->addRoute('/', [ 'presenter' => 'Home', 'action' => 'default', - null => [ + '' => [ Route::FilterIn => function (array $params): array { /* ... */ }, Route::FilterOut => function (array $params): array { /* ... */ }, ], diff --git a/application/pl/@meta.texy b/application/pl/@meta.texy new file mode 100644 index 0000000000..61ac92d1af --- /dev/null +++ b/application/pl/@meta.texy @@ -0,0 +1 @@ +{{sitename: Dokumentacja Nette}} diff --git a/application/pl/routing.texy b/application/pl/routing.texy index 49f68aa093..34577ae078 100644 --- a/application/pl/routing.texy +++ b/application/pl/routing.texy @@ -314,7 +314,7 @@ use Nette\Routing\Route; $router->addRoute('/', [ 'presenter' => 'Home', 'action' => 'default', - null => [ + '' => [ Route::FilterIn => function (array $params): array { /* ... */ }, Route::FilterOut => function (array $params): array { /* ... */ }, ], diff --git a/application/pt/@meta.texy b/application/pt/@meta.texy new file mode 100644 index 0000000000..41a853b6aa --- /dev/null +++ b/application/pt/@meta.texy @@ -0,0 +1 @@ +{{sitename: Documentação Nette}} diff --git a/application/pt/routing.texy b/application/pt/routing.texy index 659307ca93..6becfb0d3b 100644 --- a/application/pt/routing.texy +++ b/application/pt/routing.texy @@ -314,7 +314,7 @@ use Nette\Routing\Route; $router->addRoute('/', [ 'presenter' => 'Home', 'action' => 'default', - null => [ + '' => [ Route::FilterIn => function (array $params): array { /* ... */ }, Route::FilterOut => function (array $params): array { /* ... */ }, ], diff --git a/application/ro/@meta.texy b/application/ro/@meta.texy new file mode 100644 index 0000000000..9c744b37d6 --- /dev/null +++ b/application/ro/@meta.texy @@ -0,0 +1 @@ +{{sitename: Documentație Nette}} diff --git a/application/ro/routing.texy b/application/ro/routing.texy index e0b8840500..0d580d0565 100644 --- a/application/ro/routing.texy +++ b/application/ro/routing.texy @@ -314,7 +314,7 @@ use Nette\Routing\Route; $router->addRoute('/', [ 'presenter' => 'Home', 'action' => 'default', - null => [ + '' => [ Route::FilterIn => function (array $params): array { /* ... */ }, Route::FilterOut => function (array $params): array { /* ... */ }, ], diff --git a/application/ru/@meta.texy b/application/ru/@meta.texy new file mode 100644 index 0000000000..7f329adfce --- /dev/null +++ b/application/ru/@meta.texy @@ -0,0 +1 @@ +{{sitename: Документация Nette}} diff --git a/application/ru/routing.texy b/application/ru/routing.texy index dbe0c6a228..4e2896a131 100644 --- a/application/ru/routing.texy +++ b/application/ru/routing.texy @@ -314,7 +314,7 @@ use Nette\Routing\Route; $router->addRoute('/', [ 'presenter' => 'Home', 'action' => 'default', - null => [ + '' => [ Route::FilterIn => function (array $params): array { /* ... */ }, Route::FilterOut => function (array $params): array { /* ... */ }, ], diff --git a/application/sl/@meta.texy b/application/sl/@meta.texy new file mode 100644 index 0000000000..724324bee5 --- /dev/null +++ b/application/sl/@meta.texy @@ -0,0 +1 @@ +{{sitename: Nette Dokumentacija}} diff --git a/application/sl/routing.texy b/application/sl/routing.texy index dbdd549664..06c2ccee69 100644 --- a/application/sl/routing.texy +++ b/application/sl/routing.texy @@ -314,7 +314,7 @@ use Nette\Routing\Route; $router->addRoute('/', [ 'presenter' => 'Home', 'action' => 'default', - null => [ + '' => [ Route::FilterIn => function (array $params): array { /* ... */ }, Route::FilterOut => function (array $params): array { /* ... */ }, ], diff --git a/application/tr/@meta.texy b/application/tr/@meta.texy new file mode 100644 index 0000000000..8dfe82f311 --- /dev/null +++ b/application/tr/@meta.texy @@ -0,0 +1 @@ +{{sitename: Nette Dokümantasyonu}} diff --git a/application/tr/routing.texy b/application/tr/routing.texy index 5b0b81e30a..8fccd6c0b1 100644 --- a/application/tr/routing.texy +++ b/application/tr/routing.texy @@ -314,7 +314,7 @@ use Nette\Routing\Route; $router->addRoute('/', [ 'presenter' => 'Home', 'action' => 'default', - null => [ + '' => [ Route::FilterIn => function (array $params): array { /* ... */ }, Route::FilterOut => function (array $params): array { /* ... */ }, ], diff --git a/application/uk/@meta.texy b/application/uk/@meta.texy new file mode 100644 index 0000000000..96e2d9752a --- /dev/null +++ b/application/uk/@meta.texy @@ -0,0 +1 @@ +{{sitename: Документація Nette}} diff --git a/application/uk/routing.texy b/application/uk/routing.texy index a9db693215..ab3b132ccd 100644 --- a/application/uk/routing.texy +++ b/application/uk/routing.texy @@ -314,7 +314,7 @@ use Nette\Routing\Route; $router->addRoute('/', [ 'presenter' => 'Home', 'action' => 'default', - null => [ + '' => [ Route::FilterIn => function (array $params): array { /* ... */ }, Route::FilterOut => function (array $params): array { /* ... */ }, ], diff --git a/assets/bg/@meta.texy b/assets/bg/@meta.texy new file mode 100644 index 0000000000..57804a1127 --- /dev/null +++ b/assets/bg/@meta.texy @@ -0,0 +1 @@ +{{sitename: Документация на Nette}} diff --git a/assets/cs/@meta.texy b/assets/cs/@meta.texy new file mode 100644 index 0000000000..462d9add80 --- /dev/null +++ b/assets/cs/@meta.texy @@ -0,0 +1 @@ +{{sitename: Nette Dokumentace}} diff --git a/assets/de/@meta.texy b/assets/de/@meta.texy new file mode 100644 index 0000000000..b3b806b2ca --- /dev/null +++ b/assets/de/@meta.texy @@ -0,0 +1 @@ +{{sitename: Nette Dokumentation}} diff --git a/assets/el/@meta.texy b/assets/el/@meta.texy new file mode 100644 index 0000000000..88e29852c7 --- /dev/null +++ b/assets/el/@meta.texy @@ -0,0 +1 @@ +{{sitename: Nette Τεκμηρίωση}} diff --git a/assets/en/@meta.texy b/assets/en/@meta.texy new file mode 100644 index 0000000000..42471908b0 --- /dev/null +++ b/assets/en/@meta.texy @@ -0,0 +1 @@ +{{sitename: Nette Documentation}} diff --git a/assets/es/@meta.texy b/assets/es/@meta.texy new file mode 100644 index 0000000000..1670b124ad --- /dev/null +++ b/assets/es/@meta.texy @@ -0,0 +1 @@ +{{sitename: Nette Documentación}} diff --git a/assets/fr/@meta.texy b/assets/fr/@meta.texy new file mode 100644 index 0000000000..72ae4b8db8 --- /dev/null +++ b/assets/fr/@meta.texy @@ -0,0 +1 @@ +{{sitename: Documentation Nette}} diff --git a/assets/hu/@meta.texy b/assets/hu/@meta.texy new file mode 100644 index 0000000000..c172d1cda5 --- /dev/null +++ b/assets/hu/@meta.texy @@ -0,0 +1 @@ +{{sitename: Nette dokumentáció}} diff --git a/assets/it/@meta.texy b/assets/it/@meta.texy new file mode 100644 index 0000000000..4647d0c8a2 --- /dev/null +++ b/assets/it/@meta.texy @@ -0,0 +1 @@ +{{sitename: Documentazione Nette}} diff --git a/assets/ja/@meta.texy b/assets/ja/@meta.texy new file mode 100644 index 0000000000..d3c41dc3d7 --- /dev/null +++ b/assets/ja/@meta.texy @@ -0,0 +1 @@ +{{sitename: Nette ドキュメンテーション}} diff --git a/assets/pl/@meta.texy b/assets/pl/@meta.texy new file mode 100644 index 0000000000..61ac92d1af --- /dev/null +++ b/assets/pl/@meta.texy @@ -0,0 +1 @@ +{{sitename: Dokumentacja Nette}} diff --git a/assets/pt/@meta.texy b/assets/pt/@meta.texy new file mode 100644 index 0000000000..41a853b6aa --- /dev/null +++ b/assets/pt/@meta.texy @@ -0,0 +1 @@ +{{sitename: Documentação Nette}} diff --git a/assets/ro/@meta.texy b/assets/ro/@meta.texy new file mode 100644 index 0000000000..9c744b37d6 --- /dev/null +++ b/assets/ro/@meta.texy @@ -0,0 +1 @@ +{{sitename: Documentație Nette}} diff --git a/assets/ru/@meta.texy b/assets/ru/@meta.texy new file mode 100644 index 0000000000..7f329adfce --- /dev/null +++ b/assets/ru/@meta.texy @@ -0,0 +1 @@ +{{sitename: Документация Nette}} diff --git a/assets/sl/@meta.texy b/assets/sl/@meta.texy new file mode 100644 index 0000000000..724324bee5 --- /dev/null +++ b/assets/sl/@meta.texy @@ -0,0 +1 @@ +{{sitename: Nette Dokumentacija}} diff --git a/assets/tr/@meta.texy b/assets/tr/@meta.texy new file mode 100644 index 0000000000..8dfe82f311 --- /dev/null +++ b/assets/tr/@meta.texy @@ -0,0 +1 @@ +{{sitename: Nette Dokümantasyonu}} diff --git a/assets/uk/@meta.texy b/assets/uk/@meta.texy new file mode 100644 index 0000000000..96e2d9752a --- /dev/null +++ b/assets/uk/@meta.texy @@ -0,0 +1 @@ +{{sitename: Документація Nette}} diff --git a/best-practices/bg/@home.texy b/best-practices/bg/@home.texy index 77b4bf9e08..808c4d31b7 100644 --- a/best-practices/bg/@home.texy +++ b/best-practices/bg/@home.texy @@ -67,6 +67,3 @@ Nette Приложения - -{{sitename: Best Practices}} -{{leftbar: www:@menu-common}} diff --git a/best-practices/bg/@meta.texy b/best-practices/bg/@meta.texy new file mode 100644 index 0000000000..dc4e6c5b2b --- /dev/null +++ b/best-practices/bg/@meta.texy @@ -0,0 +1,2 @@ +{{sitename: Ръководства и процедури}} +{{leftbar: www:@menu-common}} diff --git a/best-practices/bg/attribute-requires.texy b/best-practices/bg/attribute-requires.texy index 8feeefe77a..c779502d44 100644 --- a/best-practices/bg/attribute-requires.texy +++ b/best-practices/bg/attribute-requires.texy @@ -175,5 +175,3 @@ class ApiPresenter extends Nette\Application\UI\Presenter ---------- Атрибутът `#[Requires]` ви дава голяма гъвкавост и контрол върху това как са достъпни вашите уеб страници. С помощта на прости, но мощни правила можете да повишите сигурността и правилното функциониране на вашето приложение. Както виждате, използването на атрибути в Nette може не само да улесни вашата работа, но и да я обезопаси. - -{{sitename: Best Practices}} diff --git a/best-practices/bg/composer.texy b/best-practices/bg/composer.texy index cd7c3805e0..2346c9485f 100644 --- a/best-practices/bg/composer.texy +++ b/best-practices/bg/composer.texy @@ -280,5 +280,3 @@ Composer е тясно свързан с инструмента за верси ```shell composer -g config preferred-install dist ``` - -{{sitename: Best Practices}} diff --git a/best-practices/bg/creating-editing-form.texy b/best-practices/bg/creating-editing-form.texy index 65f651bba7..5f4f84a06c 100644 --- a/best-practices/bg/creating-editing-form.texy +++ b/best-practices/bg/creating-editing-form.texy @@ -203,4 +203,3 @@ class RecordPresenter extends Nette\Application\UI\Presenter ``` {{priority: -1}} -{{sitename: Best Practices}} diff --git a/best-practices/bg/dynamic-snippets.texy b/best-practices/bg/dynamic-snippets.texy index e872d93897..c8baa990be 100644 --- a/best-practices/bg/dynamic-snippets.texy +++ b/best-practices/bg/dynamic-snippets.texy @@ -171,4 +171,3 @@ protected function createComponentLikeControl() Почти сме готови: приложението вече ще работи с AJAX. И тук трябва да оптимизираме приложението, защото поради използването на Nette Database, при обработката на сигнала ненужно се зареждат всички статии от базата данни вместо само една. Предимството обаче е, че те няма да бъдат рендирани, тъй като ще се рендира само нашият компонент. {{priority: -1}} -{{sitename: Best Practices}} diff --git a/best-practices/bg/editors-and-tools.texy b/best-practices/bg/editors-and-tools.texy index a6a88722d8..89751ce259 100644 --- a/best-practices/bg/editors-and-tools.texy +++ b/best-practices/bg/editors-and-tools.texy @@ -82,5 +82,3 @@ Requirements Checker ==================== Това беше инструмент, който тестваше средата за изпълнение на сървъра и информираше дали (и до каква степен) е възможно да се използва framework-ът. В момента Nette може да се използва на всеки сървър, който има минималната изисквана версия на PHP. - -{{sitename: Best Practices}} diff --git a/best-practices/bg/form-reuse.texy b/best-practices/bg/form-reuse.texy index b8724ecb50..1af34cdd6f 100644 --- a/best-practices/bg/form-reuse.texy +++ b/best-practices/bg/form-reuse.texy @@ -346,5 +346,3 @@ class MyPresenter extends Nette\Application\UI\Presenter } } ``` - -{{sitename: Best Practices}} diff --git a/best-practices/bg/inject-method-attribute.texy b/best-practices/bg/inject-method-attribute.texy index cfbb8cbf70..2d72ead00c 100644 --- a/best-practices/bg/inject-method-attribute.texy +++ b/best-practices/bg/inject-method-attribute.texy @@ -59,6 +59,3 @@ class MyPresenter extends Nette\Application\UI\Presenter Предимството на този начин на предаване на зависимости беше много икономичната форма на запис. Въпреки това, с появата на [constructor property promotion |https://blog.nette.org/bg/php-8-0-complete-overview-of-news#toc-constructor-property-promotion], изглежда по-лесно да се използва конструктор. От друга страна, този начин страда от същите недостатъци като предаването на зависимости към свойства като цяло: нямаме контрол над промените в променливата и същевременно променливата става част от публичния интерфейс на класа, което е нежелателно. - - -{{sitename: Best Practices}} diff --git a/best-practices/bg/lets-create-contact-form.texy b/best-practices/bg/lets-create-contact-form.texy index 9069f217f6..9070371fe2 100644 --- a/best-practices/bg/lets-create-contact-form.texy +++ b/best-practices/bg/lets-create-contact-form.texy @@ -219,6 +219,3 @@ parameters: ``` И е готово! - - -{{sitename: Best Practices}} diff --git a/best-practices/bg/microsites.texy b/best-practices/bg/microsites.texy index 4b57abec8c..e29edcb2ed 100644 --- a/best-practices/bg/microsites.texy +++ b/best-practices/bg/microsites.texy @@ -61,5 +61,3 @@ PHP кодът в `index.php` първо [подготвя средата |boots - Понякога може да ви е полезно [кеширането|caching:], например ако изтегляте и показвате фийдове. В днешно време, когато скоростта и ефективността са ключови, е важно да имате инструменти, които ви позволяват да постигнете резултати без излишно забавяне. Nette framework ви предлага точно това - бърза разработка, сигурност и широк набор от инструменти, като Tracy и Latte, които опростяват процеса. Достатъчно е да инсталирате няколко Nette пакета и изграждането на такъв микросайт изведнъж става напълно лесно. И знаете, че никъде не се крие никаква дупка в сигурността. - -{{sitename: Best Practices}} diff --git a/best-practices/bg/pagination.texy b/best-practices/bg/pagination.texy index 16e609ce25..15a33b739e 100644 --- a/best-practices/bg/pagination.texy +++ b/best-practices/bg/pagination.texy @@ -271,4 +271,3 @@ class HomePresenter extends Nette\Application\UI\Presenter По този начин внедрихме механизъм за пагиниране без използване на Paginator. {{priority: -1}} -{{sitename: Best Practices}} diff --git a/best-practices/bg/passing-settings-to-presenters.texy b/best-practices/bg/passing-settings-to-presenters.texy index de14fd76cf..076be18938 100644 --- a/best-practices/bg/passing-settings-to-presenters.texy +++ b/best-practices/bg/passing-settings-to-presenters.texy @@ -47,5 +47,3 @@ class MyPresenter extends Nette\Application\UI\Presenter } } ``` - -{{sitename: Best Practices}} diff --git a/best-practices/bg/post-links.texy b/best-practices/bg/post-links.texy index 67f354a86c..452bb3b18a 100644 --- a/best-practices/bg/post-links.texy +++ b/best-practices/bg/post-links.texy @@ -54,6 +54,3 @@ public function handleDelete(int $id): void ``` Този подход не само подобрява сигурността на вашето приложение, но също така допринася за спазването на правилните уеб стандарти и практики. Чрез използването на методи POST за действия, променящи състоянието, ще постигнете по-стабилно и по-сигурно приложение. - - -{{sitename: Best Practices}} diff --git a/best-practices/bg/presenter-traits.texy b/best-practices/bg/presenter-traits.texy index 4567d3f079..c2cf88f074 100644 --- a/best-practices/bg/presenter-traits.texy +++ b/best-practices/bg/presenter-traits.texy @@ -45,6 +45,3 @@ class ArticlePresenter extends Nette\Application\UI\Presenter use RequireLoggedUser; } ``` - - -{{sitename: Best Practices}} diff --git a/best-practices/bg/restore-request.texy b/best-practices/bg/restore-request.texy index f687d89ef5..191350748d 100644 --- a/best-practices/bg/restore-request.texy +++ b/best-practices/bg/restore-request.texy @@ -60,4 +60,3 @@ class SignPresenter extends Nette\Application\UI\Presenter Ако обаче ключът е невалиден (например вече не съществува в сесията), методът не прави нищо. Следователно следва извикването на `$this->redirect('Admin:')`, което пренасочва към `AdminPresenter`. {{priority: -1}} -{{sitename: Best Practices}} diff --git a/best-practices/cs/@home.texy b/best-practices/cs/@home.texy index 84d96c8a34..612d75048f 100644 --- a/best-practices/cs/@home.texy +++ b/best-practices/cs/@home.texy @@ -67,6 +67,3 @@ Stovky záznamů z Posledních sobot a videí o Nette naleznete pod jednou stře - -{{sitename: Best Practices}} -{{leftbar: www:@menu-common}} diff --git a/best-practices/cs/@meta.texy b/best-practices/cs/@meta.texy new file mode 100644 index 0000000000..0c9a1e9689 --- /dev/null +++ b/best-practices/cs/@meta.texy @@ -0,0 +1,2 @@ +{{sitename: Návody a postupy}} +{{leftbar: www:@menu-common}} diff --git a/best-practices/cs/attribute-requires.texy b/best-practices/cs/attribute-requires.texy index 611855f14b..682d1640a5 100644 --- a/best-practices/cs/attribute-requires.texy +++ b/best-practices/cs/attribute-requires.texy @@ -175,5 +175,3 @@ Závěr ----- Atribut `#[Requires]` vám dává velkou flexibilitu a kontrolu nad tím, jak jsou vaše webové stránky přístupné. Pomocí jednoduchých, ale mocných pravidel můžete zvýšit bezpečnost a správné fungování vaší aplikace. Jak vidíte, použití atributů v Nette může vaši práci nejen usnadnit, ale i zabezpečit. - -{{sitename: Best Practices}} diff --git a/best-practices/cs/composer.texy b/best-practices/cs/composer.texy index 37d208b6f2..aebe726bbc 100644 --- a/best-practices/cs/composer.texy +++ b/best-practices/cs/composer.texy @@ -280,5 +280,3 @@ Composer je úzce propojený s verzovacím nástrojem [Git |https://git-scm.com] ```shell composer -g config preferred-install dist ``` - -{{sitename: Best Practices}} diff --git a/best-practices/cs/creating-editing-form.texy b/best-practices/cs/creating-editing-form.texy index e8a713521a..d43c67faf8 100644 --- a/best-practices/cs/creating-editing-form.texy +++ b/best-practices/cs/creating-editing-form.texy @@ -29,11 +29,11 @@ class RecordPresenter extends Nette\Application\UI\Presenter // ... přidáme políčka formuláře ... - $form->onSuccess[] = [$this, 'recordFormSucceeded']; + $form->onSuccess[] = $this->recordFormSucceeded(...); return $form; } - public function recordFormSucceeded(Form $form, array $data): void + private function recordFormSucceeded(Form $form, array $data): void { $this->facade->add($data); // přidání záznamu do databáze $this->flashMessage('Successfully added'); @@ -91,11 +91,11 @@ class RecordPresenter extends Nette\Application\UI\Presenter // ... přidáme políčka formuláře ... $form->setDefaults($this->record); // nastavení výchozích hodnot - $form->onSuccess[] = [$this, 'recordFormSucceeded']; + $form->onSuccess[] = $this->recordFormSucceeded(...); return $form; } - public function recordFormSucceeded(Form $form, array $data): void + private function recordFormSucceeded(Form $form, array $data): void { $this->facade->update($this->record->id, $data); // aktualizace záznamu $this->flashMessage('Successfully updated'); @@ -130,7 +130,6 @@ Záznam si uložíme do property `$record`, abychom jej měli k dispozici v meto $this->facade->update($id, $data); // ... } -} ``` Nicméně, a to by mělo být **nejdůležitejším poznatkem celého kódu**, musíme se při tvorbě formuláře ujistit, že akce je skutečně `edit`. Protože jinak by ověření v metodě `actionEdit()` vůbec neproběhlo! @@ -153,7 +152,7 @@ class RecordPresenter extends Nette\Application\UI\Presenter public function actionAdd(): void { $form = $this->getComponent('recordForm'); - $form->onSuccess[] = [$this, 'addingFormSucceeded']; + $form->onSuccess[] = $this->addingFormSucceeded(...); } public function actionEdit(int $id): void @@ -168,7 +167,7 @@ class RecordPresenter extends Nette\Application\UI\Presenter $form = $this->getComponent('recordForm'); $form->setDefaults($record); // nastavení výchozích hodnot - $form->onSuccess[] = [$this, 'editingFormSucceeded']; + $form->onSuccess[] = $this->editingFormSucceeded(...); } protected function createComponentRecordForm(): Form @@ -185,14 +184,14 @@ class RecordPresenter extends Nette\Application\UI\Presenter return $form; } - public function addingFormSucceeded(Form $form, array $data): void + private function addingFormSucceeded(Form $form, array $data): void { $this->facade->add($data); // přidání záznamu do databáze $this->flashMessage('Successfully added'); $this->redirect('...'); } - public function editingFormSucceeded(Form $form, array $data): void + private function editingFormSucceeded(Form $form, array $data): void { $id = (int) $this->getParameter('id'); $this->facade->update($id, $data); // aktualizace záznamu @@ -203,4 +202,3 @@ class RecordPresenter extends Nette\Application\UI\Presenter ``` {{priority: -1}} -{{sitename: Best Practices}} diff --git a/best-practices/cs/dynamic-snippets.texy b/best-practices/cs/dynamic-snippets.texy index cc50c47acb..104844e59c 100644 --- a/best-practices/cs/dynamic-snippets.texy +++ b/best-practices/cs/dynamic-snippets.texy @@ -171,4 +171,3 @@ protected function createComponentLikeControl() Máme téměř hotovo: aplikace nyní bude fungovat AJAXově. I zde nás čeká aplikaci optimalizovat, protože vzhledem k použití Nette Database se při zpracování signálu zbytečně načtou všechny články z databáze namísto jednoho. Výhodou však je, že nedojde k jejich vykreslování, protože se vyrenderuje skutečně jen naše komponenta. {{priority: -1}} -{{sitename: Best Practices}} diff --git a/best-practices/cs/editors-and-tools.texy b/best-practices/cs/editors-and-tools.texy index a299c3f5eb..efbbd772ba 100644 --- a/best-practices/cs/editors-and-tools.texy +++ b/best-practices/cs/editors-and-tools.texy @@ -13,9 +13,9 @@ Rozhodně doporučujeme pro vývoj používat plnohodnotné IDE, jako je třeba **NetBeans IDE** má podporu pro Nette, Latte a NEON už vestavěnou. **PhpStorm**: nainstalujte si tyto pluginy v `Settings > Plugins > Marketplace` -- Nette framework helpers -- Latte -- NEON support +- [Nette |https://plugins.jetbrains.com/plugin/28342-nette] +- [Latte |https://plugins.jetbrains.com/plugin/24218-latte-support] nebo [Latte Pro |https://plugins.jetbrains.com/plugin/19661-latte-pro] +- [NEON |https://plugins.jetbrains.com/plugin/28338-neon] nebo [NEON / Nette support |https://plugins.jetbrains.com/plugin/18387-neon-nette-support] - Nette Tester **VS Code**: najděte v marketplace "Nette Latte + Neon" plugin. @@ -82,5 +82,3 @@ Requirements Checker ==================== Šlo o nástroj, který testoval běhové prostředí serveru a informoval, zda (a do jaké míry) je možné framework používat. V současnosti je Nette možné používat na každém serveru, který má minimální požadovanou verzi PHP. - -{{sitename: Best Practices}} diff --git a/best-practices/cs/form-reuse.texy b/best-practices/cs/form-reuse.texy index b1310fba6b..ac95ca2617 100644 --- a/best-practices/cs/form-reuse.texy +++ b/best-practices/cs/form-reuse.texy @@ -193,11 +193,11 @@ class EditFormFactory $form->addText('title', 'Titulek:'); // zde se přidávají další formulářová pole $form->addSubmit('send', 'Odeslat'); - $form->onSuccess[] = [$this, 'processForm']; + $form->onSuccess[] = $this->processForm(...); return $form; } - public function processForm(Form $form, array $data): void + private function processForm(Form $form, array $data): void { try { // zpracování odeslaných dat @@ -284,12 +284,12 @@ class EditControl extends Nette\Application\UI\Control $form->addText('title', 'Titulek:'); // zde se přidávají další formulářová pole $form->addSubmit('send', 'Odeslat'); - $form->onSuccess[] = [$this, 'processForm']; + $form->onSuccess[] = $this->processForm(...); return $form; } - public function processForm(Form $form, array $data): void + private function processForm(Form $form, array $data): void { try { // zpracování odeslaných dat @@ -346,5 +346,3 @@ class MyPresenter extends Nette\Application\UI\Presenter } } ``` - -{{sitename: Best Practices}} diff --git a/best-practices/cs/inject-method-attribute.texy b/best-practices/cs/inject-method-attribute.texy index e12dcbfffd..f831f0535f 100644 --- a/best-practices/cs/inject-method-attribute.texy +++ b/best-practices/cs/inject-method-attribute.texy @@ -59,6 +59,3 @@ class MyPresenter extends Nette\Application\UI\Presenter Výhodou tohoto způsobu předávání závislostí byla velice úsporná podoba zápisu. Nicméně s příchodem [constructor property promotion |https://blog.nette.org/cs/php-8-0-kompletni-prehled-novinek#toc-constructor-property-promotion] se jeví snazší použít konstruktor. Naopak tento způsob trpí stejnými nedostatky, jako předávání závislosti do properties obecně: nemáme kontrolu nad změnami v proměnné a zároveň se proměnná stává součástí veřejného rozhraní třídy, což je nežádnoucí. - - -{{sitename: Best Practices}} diff --git a/best-practices/cs/lets-create-contact-form.texy b/best-practices/cs/lets-create-contact-form.texy index a56d0d61f2..23fde0f0c5 100644 --- a/best-practices/cs/lets-create-contact-form.texy +++ b/best-practices/cs/lets-create-contact-form.texy @@ -24,11 +24,11 @@ class HomePresenter extends Presenter $form->addTextarea('message', 'Zpráva:') ->setRequired('Zadejte zprávu'); $form->addSubmit('send', 'Odeslat'); - $form->onSuccess[] = [$this, 'contactFormSucceeded']; + $form->onSuccess[] = $this->contactFormSucceeded(...); return $form; } - public function contactFormSucceeded(Form $form, $data): void + private function contactFormSucceeded(Form $form, $data): void { // odeslání emailu } @@ -48,9 +48,6 @@ Komponentu `contactForm` necháme vykreslit v šabloně `Home/default.latte`: Pro samotné odeslání emailu vytvoříme novou třídu, kterou nazveme `ContactFacade` a umístíme ji do souboru `app/Model/ContactFacade.php`: ```php -onSuccess[] = [$this, 'signInFormSubmitted']; + $form->onSuccess[] = $this->signInFormSubmitted(...); return $form; } - public function signInFormSubmitted($form) + private function signInFormSubmitted($form) { // ... tady uživatele přihlásíme ... @@ -60,4 +60,3 @@ Metodě `restoreRequest()` předáme klíč uloženého požadavku a ona přesm Pokud je ale klíč neplatný (například už v session neexistuje), metoda neudělá nic. Následuje tedy volání `$this->redirect('Admin:')`, které přesměruje na `AdminPresenter`. {{priority: -1}} -{{sitename: Best Practices}} diff --git a/best-practices/de/@home.texy b/best-practices/de/@home.texy index 5e611bb9b7..d855293435 100644 --- a/best-practices/de/@home.texy +++ b/best-practices/de/@home.texy @@ -67,6 +67,3 @@ Hunderte von Aufzeichnungen von "Poslední sobota" und Videos über Nette finden - -{{sitename: Best Practices}} -{{leftbar: www:@menu-common}} diff --git a/best-practices/de/@meta.texy b/best-practices/de/@meta.texy new file mode 100644 index 0000000000..c3bc189de7 --- /dev/null +++ b/best-practices/de/@meta.texy @@ -0,0 +1,2 @@ +{{sitename: Anleitungen und Verfahren}} +{{leftbar: www:@menu-common}} diff --git a/best-practices/de/attribute-requires.texy b/best-practices/de/attribute-requires.texy index 054c34d812..b6a5b9f6c2 100644 --- a/best-practices/de/attribute-requires.texy +++ b/best-practices/de/attribute-requires.texy @@ -175,5 +175,3 @@ Fazit ----- Das Attribut `#[Requires]` gibt Ihnen große Flexibilität und Kontrolle darüber, wie auf Ihre Webseiten zugegriffen wird. Mit einfachen, aber leistungsstarken Regeln können Sie die Sicherheit und die korrekte Funktion Ihrer Anwendung erhöhen. Wie Sie sehen, kann die Verwendung von Attributen in Nette Ihre Arbeit nicht nur erleichtern, sondern auch sicherer machen. - -{{sitename: Best Practices}} diff --git a/best-practices/de/composer.texy b/best-practices/de/composer.texy index 35ae323e70..554def763b 100644 --- a/best-practices/de/composer.texy +++ b/best-practices/de/composer.texy @@ -280,5 +280,3 @@ Composer ist eng mit dem Versionierungswerkzeug [Git |https://git-scm.com] verbu ```shell composer -g config preferred-install dist ``` - -{{sitename: Best Practices}} diff --git a/best-practices/de/creating-editing-form.texy b/best-practices/de/creating-editing-form.texy index ee98f56405..4238bf13fa 100644 --- a/best-practices/de/creating-editing-form.texy +++ b/best-practices/de/creating-editing-form.texy @@ -203,4 +203,3 @@ class RecordPresenter extends Nette\Application\UI\Presenter ``` {{priority: -1}} -{{sitename: Best Practices}} diff --git a/best-practices/de/dynamic-snippets.texy b/best-practices/de/dynamic-snippets.texy index 085d4e735f..b4ea7a67d5 100644 --- a/best-practices/de/dynamic-snippets.texy +++ b/best-practices/de/dynamic-snippets.texy @@ -171,4 +171,3 @@ Das View-Template wird auf das notwendige Minimum reduziert (und völlig frei vo Wir sind fast fertig: Die Anwendung wird nun AJAX-fähig funktionieren. Auch hier müssen wir die Anwendung optimieren, da aufgrund der Verwendung von Nette Database bei der Signalverarbeitung unnötigerweise alle Artikel aus der Datenbank anstelle von nur einem geladen werden. Der Vorteil ist jedoch, dass es nicht zu deren Rendern kommt, da tatsächlich nur unsere Komponente gerendert wird. {{priority: -1}} -{{sitename: Best Practices}} diff --git a/best-practices/de/editors-and-tools.texy b/best-practices/de/editors-and-tools.texy index ea98e74731..bda0c9c7fb 100644 --- a/best-practices/de/editors-and-tools.texy +++ b/best-practices/de/editors-and-tools.texy @@ -82,5 +82,3 @@ Requirements Checker ==================== Dies war ein Werkzeug, das die Laufzeitumgebung des Servers testete und informierte, ob (und inwieweit) das Framework verwendet werden kann. Derzeit kann Nette auf jedem Server verwendet werden, der die minimal erforderliche PHP-Version hat. - -{{sitename: Best Practices}} diff --git a/best-practices/de/form-reuse.texy b/best-practices/de/form-reuse.texy index 417a3bf484..0da82ed0e4 100644 --- a/best-practices/de/form-reuse.texy +++ b/best-practices/de/form-reuse.texy @@ -346,5 +346,3 @@ class MyPresenter extends Nette\Application\UI\Presenter } } ``` - -{{sitename: Best Practices}} diff --git a/best-practices/de/inject-method-attribute.texy b/best-practices/de/inject-method-attribute.texy index 151a0304fb..45788eca01 100644 --- a/best-practices/de/inject-method-attribute.texy +++ b/best-practices/de/inject-method-attribute.texy @@ -59,6 +59,3 @@ class MyPresenter extends Nette\Application\UI\Presenter Der Vorteil dieser Art der Abhängigkeitsübergabe war die sehr sparsame Schreibweise. Mit der Einführung von [Constructor Property Promotion |https://blog.nette.org/de/php-8-0-kompletter-ueberblick-ueber-neuerungen#toc-constructor-property-promotion] erscheint es jedoch einfacher, den Konstruktor zu verwenden. Im Gegenteil leidet diese Methode unter denselben Nachteilen wie die Übergabe von Abhängigkeiten an Eigenschaften im Allgemeinen: Wir haben keine Kontrolle über Änderungen in der Variablen, und gleichzeitig wird die Variable Teil der öffentlichen Schnittstelle der Klasse, was unerwünscht ist. - - -{{sitename: Best Practices}} diff --git a/best-practices/de/lets-create-contact-form.texy b/best-practices/de/lets-create-contact-form.texy index dcdb943252..998313e20f 100644 --- a/best-practices/de/lets-create-contact-form.texy +++ b/best-practices/de/lets-create-contact-form.texy @@ -219,6 +219,3 @@ parameters: ``` Und fertig! - - -{{sitename: Best Practices}} diff --git a/best-practices/de/microsites.texy b/best-practices/de/microsites.texy index 289a0cc918..71eac0ad76 100644 --- a/best-practices/de/microsites.texy +++ b/best-practices/de/microsites.texy @@ -61,5 +61,3 @@ Warum Nette für Microsites verwenden? - Manchmal kann Ihnen [Caching|caching:] nützlich sein, zum Beispiel wenn Sie Feeds herunterladen und anzeigen. In der heutigen Zeit, in der Geschwindigkeit und Effizienz entscheidend sind, ist es wichtig, Werkzeuge zu haben, die es Ihnen ermöglichen, Ergebnisse ohne unnötige Verzögerung zu erzielen. Das Nette Framework bietet Ihnen genau das - schnelle Entwicklung, Sicherheit und eine breite Palette von Werkzeugen wie Tracy und Latte, die den Prozess vereinfachen. Installieren Sie einfach ein paar Nette-Pakete und der Aufbau einer solchen Microsite ist plötzlich ein Kinderspiel. Und Sie wissen, dass sich nirgendwo eine Sicherheitslücke verbirgt. - -{{sitename: Best Practices}} diff --git a/best-practices/de/pagination.texy b/best-practices/de/pagination.texy index 8484097040..17aabcacc3 100644 --- a/best-practices/de/pagination.texy +++ b/best-practices/de/pagination.texy @@ -271,4 +271,3 @@ Da wir nun keinen Paginator an das Template senden, passen wir den Teil an, der Auf diese Weise haben wir den Paginierungsmechanismus ohne Verwendung des Paginators implementiert. {{priority: -1}} -{{sitename: Best Practices}} diff --git a/best-practices/de/passing-settings-to-presenters.texy b/best-practices/de/passing-settings-to-presenters.texy index 216b4823b6..d84c9fb780 100644 --- a/best-practices/de/passing-settings-to-presenters.texy +++ b/best-practices/de/passing-settings-to-presenters.texy @@ -47,5 +47,3 @@ class MyPresenter extends Nette\Application\UI\Presenter } } ``` - -{{sitename: Best Practices}} diff --git a/best-practices/de/post-links.texy b/best-practices/de/post-links.texy index f340fa81ab..f4f90e1f24 100644 --- a/best-practices/de/post-links.texy +++ b/best-practices/de/post-links.texy @@ -54,6 +54,3 @@ public function handleDelete(int $id): void ``` Dieser Ansatz verbessert nicht nur die Sicherheit Ihrer Anwendung, sondern trägt auch zur Einhaltung korrekter Webstandards und Praktiken bei. Durch die Verwendung von POST-Methoden für zustandsändernde Aktionen erreichen Sie eine robustere und sicherere Anwendung. - - -{{sitename: Best Practices}} diff --git a/best-practices/de/presenter-traits.texy b/best-practices/de/presenter-traits.texy index 3ef62a5726..e6cf4290dc 100644 --- a/best-practices/de/presenter-traits.texy +++ b/best-practices/de/presenter-traits.texy @@ -45,6 +45,3 @@ class ArticlePresenter extends Nette\Application\UI\Presenter use RequireLoggedUser; } ``` - - -{{sitename: Best Practices}} diff --git a/best-practices/de/restore-request.texy b/best-practices/de/restore-request.texy index 50c90b7a6b..957f7c6605 100644 --- a/best-practices/de/restore-request.texy +++ b/best-practices/de/restore-request.texy @@ -60,4 +60,3 @@ Wir übergeben der Methode `restoreRequest()` den Schlüssel der gespeicherten A Wenn der Schlüssel jedoch ungültig ist (z. B. nicht mehr in der Session existiert oder der Benutzer nicht übereinstimmt), tut die Methode nichts. Es folgt also der Aufruf `$this->redirect('Admin:')`, der zum `AdminPresenter` (oder einer anderen Standardseite nach dem Login) weiterleitet. {{priority: -1}} -{{sitename: Best Practices}} diff --git a/best-practices/el/@home.texy b/best-practices/el/@home.texy index ad79a76071..0e8088a224 100644 --- a/best-practices/el/@home.texy +++ b/best-practices/el/@home.texy @@ -67,6 +67,3 @@ - -{{sitename: Best Practices}} -{{leftbar: www:@menu-common}} diff --git a/best-practices/el/@meta.texy b/best-practices/el/@meta.texy new file mode 100644 index 0000000000..9ae15ea14a --- /dev/null +++ b/best-practices/el/@meta.texy @@ -0,0 +1,2 @@ +{{sitename: Οδηγοί και διαδικασίες}} +{{leftbar: www:@menu-common}} diff --git a/best-practices/el/attribute-requires.texy b/best-practices/el/attribute-requires.texy index a91a38d7a9..6a3211185c 100644 --- a/best-practices/el/attribute-requires.texy +++ b/best-practices/el/attribute-requires.texy @@ -175,5 +175,3 @@ class ApiPresenter extends Nette\Application\UI\Presenter ---------- Το attribute `#[Requires]` σας δίνει μεγάλη ευελιξία και έλεγχο στο πώς είναι προσβάσιμες οι ιστοσελίδες σας. Χρησιμοποιώντας απλούς αλλά ισχυρούς κανόνες, μπορείτε να αυξήσετε την ασφάλεια και τη σωστή λειτουργία της εφαρμογής σας. Όπως βλέπετε, η χρήση attributes στο Nette μπορεί όχι μόνο να διευκολύνει τη δουλειά σας, αλλά και να την ασφαλίσει. - -{{sitename: Best Practices}} diff --git a/best-practices/el/composer.texy b/best-practices/el/composer.texy index 1a50f9f416..9e0a6a7715 100644 --- a/best-practices/el/composer.texy +++ b/best-practices/el/composer.texy @@ -280,5 +280,3 @@ composer thanks ```shell composer -g config preferred-install dist ``` - -{{sitename: Best Practices}} diff --git a/best-practices/el/creating-editing-form.texy b/best-practices/el/creating-editing-form.texy index 039b46fa99..4566a81628 100644 --- a/best-practices/el/creating-editing-form.texy +++ b/best-practices/el/creating-editing-form.texy @@ -203,4 +203,3 @@ class RecordPresenter extends Nette\Application\UI\Presenter ``` {{priority: -1}} -{{sitename: Best Practices}} diff --git a/best-practices/el/dynamic-snippets.texy b/best-practices/el/dynamic-snippets.texy index 618a00787c..134ee63491 100644 --- a/best-practices/el/dynamic-snippets.texy +++ b/best-practices/el/dynamic-snippets.texy @@ -171,4 +171,3 @@ protected function createComponentLikeControl() Έχουμε σχεδόν τελειώσει: η εφαρμογή τώρα θα λειτουργεί με AJAX. Και εδώ μας περιμένει η βελτιστοποίηση της εφαρμογής, επειδή λόγω της χρήσης του Nette Database, κατά την επεξεργασία του σήματος φορτώνονται άσκοπα όλα τα άρθρα από τη βάση δεδομένων αντί για ένα. Το πλεονέκτημα όμως είναι ότι δεν θα γίνει η σχεδίασή τους, επειδή θα αποδοθεί πραγματικά μόνο το component μας. {{priority: -1}} -{{sitename: Best Practices}} diff --git a/best-practices/el/editors-and-tools.texy b/best-practices/el/editors-and-tools.texy index 85eb06f8b5..a5d46f739c 100644 --- a/best-practices/el/editors-and-tools.texy +++ b/best-practices/el/editors-and-tools.texy @@ -82,5 +82,3 @@ Requirements Checker ==================== Ήταν ένα εργαλείο που δοκίμαζε το περιβάλλον εκτέλεσης του server και ενημέρωνε αν (και σε ποιο βαθμό) ήταν δυνατό να χρησιμοποιηθεί το framework. Επί του παρόντος, το Nette μπορεί να χρησιμοποιηθεί σε κάθε server που έχει την ελάχιστη απαιτούμενη έκδοση PHP. - -{{sitename: Best Practices}} diff --git a/best-practices/el/form-reuse.texy b/best-practices/el/form-reuse.texy index 76e7dfe7a4..28f0bf1b38 100644 --- a/best-practices/el/form-reuse.texy +++ b/best-practices/el/form-reuse.texy @@ -346,5 +346,3 @@ class MyPresenter extends Nette\Application\UI\Presenter } } ``` - -{{sitename: Best Practices}} diff --git a/best-practices/el/inject-method-attribute.texy b/best-practices/el/inject-method-attribute.texy index d8a6f6a25b..a13bfcff48 100644 --- a/best-practices/el/inject-method-attribute.texy +++ b/best-practices/el/inject-method-attribute.texy @@ -59,6 +59,3 @@ class MyPresenter extends Nette\Application\UI\Presenter Το πλεονέκτημα αυτού του τρόπου περάσματος εξαρτήσεων ήταν η πολύ οικονομική μορφή γραφής. Ωστόσο, με την έλευση του [constructor property promotion |https://blog.nette.org/el/php-8-0-complete-overview-of-news#toc-constructor-property-promotion], φαίνεται ευκολότερο να χρησιμοποιηθεί ο constructor. Αντίθετα, αυτός ο τρόπος πάσχει από τις ίδιες αδυναμίες με το πέρασμα εξαρτήσεων σε properties γενικά: δεν έχουμε έλεγχο στις αλλαγές στη μεταβλητή και ταυτόχρονα η μεταβλητή γίνεται μέρος του δημόσιου interface της κλάσης, πράγμα που είναι ανεπιθύμητο. - - -{{sitename: Best Practices}} diff --git a/best-practices/el/lets-create-contact-form.texy b/best-practices/el/lets-create-contact-form.texy index c713cadb6d..fa4e52cc69 100644 --- a/best-practices/el/lets-create-contact-form.texy +++ b/best-practices/el/lets-create-contact-form.texy @@ -219,6 +219,3 @@ parameters: ``` Και τελειώσαμε! - - -{{sitename: Best Practices}} diff --git a/best-practices/el/microsites.texy b/best-practices/el/microsites.texy index 0b78aab73a..2224119362 100644 --- a/best-practices/el/microsites.texy +++ b/best-practices/el/microsites.texy @@ -61,5 +61,3 @@ $container->getByType(Nette\Application\Application::class)->run(); - Μερικές φορές μπορεί να σας φανεί χρήσιμο το [caching |caching:], για παράδειγμα αν κατεβάζετε και εμφανίζετε feeds. Στη σημερινή εποχή, όπου η ταχύτητα και η αποτελεσματικότητα είναι καθοριστικής σημασίας, είναι σημαντικό να έχετε εργαλεία που σας επιτρέπουν να επιτύχετε αποτελέσματα χωρίς περιττές καθυστερήσεις. Το Nette framework σας προσφέρει ακριβώς αυτό - γρήγορη ανάπτυξη, ασφάλεια και ένα ευρύ φάσμα εργαλείων, όπως το Tracy και το Latte, που απλοποιούν τη διαδικασία. Αρκεί να εγκαταστήσετε μερικά πακέτα Nette και η κατασκευή ενός τέτοιου microsite γίνεται ξαφνικά παιχνιδάκι. Και ξέρετε ότι πουθενά δεν κρύβεται καμία τρύπα ασφαλείας. - -{{sitename: Best Practices}} diff --git a/best-practices/el/pagination.texy b/best-practices/el/pagination.texy index 1a8b3e2071..cdefb763e4 100644 --- a/best-practices/el/pagination.texy +++ b/best-practices/el/pagination.texy @@ -271,4 +271,3 @@ class HomePresenter extends Nette\Application\UI\Presenter Με αυτόν τον τρόπο υλοποιήσαμε τον μηχανισμό σελίδωσης χωρίς τη χρήση του Paginator. {{priority: -1}} -{{sitename: Best Practices}} diff --git a/best-practices/el/passing-settings-to-presenters.texy b/best-practices/el/passing-settings-to-presenters.texy index 5b5356358b..f600bbb498 100644 --- a/best-practices/el/passing-settings-to-presenters.texy +++ b/best-practices/el/passing-settings-to-presenters.texy @@ -47,5 +47,3 @@ class MyPresenter extends Nette\Application\UI\Presenter } } ``` - -{{sitename: Best Practices}} diff --git a/best-practices/el/post-links.texy b/best-practices/el/post-links.texy index 2454034772..a6147e263a 100644 --- a/best-practices/el/post-links.texy +++ b/best-practices/el/post-links.texy @@ -54,6 +54,3 @@ public function handleDelete(int $id): void ``` Αυτή η προσέγγιση όχι μόνο βελτιώνει την ασφάλεια της εφαρμογής σας, αλλά συμβάλλει επίσης στην τήρηση των σωστών web προτύπων και πρακτικών. Χρησιμοποιώντας τις μεθόδους POST για ενέργειες που αλλάζουν την κατάσταση, επιτυγχάνετε μια πιο στιβαρή και ασφαλή εφαρμογή. - - -{{sitename: Best Practices}} diff --git a/best-practices/el/presenter-traits.texy b/best-practices/el/presenter-traits.texy index 352d127baa..b5c9e24f28 100644 --- a/best-practices/el/presenter-traits.texy +++ b/best-practices/el/presenter-traits.texy @@ -45,6 +45,3 @@ class ArticlePresenter extends Nette\Application\UI\Presenter use RequireLoggedUser; } ``` - - -{{sitename: Best Practices}} diff --git a/best-practices/el/restore-request.texy b/best-practices/el/restore-request.texy index 28802cb67d..631a0c432b 100644 --- a/best-practices/el/restore-request.texy +++ b/best-practices/el/restore-request.texy @@ -60,4 +60,3 @@ class SignPresenter extends Nette\Application\UI\Presenter Αν όμως το κλειδί είναι άκυρο (για παράδειγμα δεν υπάρχει πλέον στο session), η μέθοδος δεν κάνει τίποτα. Ακολουθεί επομένως η κλήση `$this->redirect('Admin:')`, η οποία ανακατευθύνει στον `AdminPresenter`. {{priority: -1}} -{{sitename: Best Practices}} diff --git a/best-practices/en/@home.texy b/best-practices/en/@home.texy index 651c9a82a7..04508b55aa 100644 --- a/best-practices/en/@home.texy +++ b/best-practices/en/@home.texy @@ -67,6 +67,3 @@ Hundreds of recordings from Last Saturday meetups and videos about Nette can be - -{{sitename: Best Practices}} -{{leftbar: www:@menu-common}} diff --git a/best-practices/en/@meta.texy b/best-practices/en/@meta.texy new file mode 100644 index 0000000000..10c126830b --- /dev/null +++ b/best-practices/en/@meta.texy @@ -0,0 +1,2 @@ +{{sitename: Tutorials and Best Practices}} +{{leftbar: www:@menu-common}} diff --git a/best-practices/en/attribute-requires.texy b/best-practices/en/attribute-requires.texy index 75e296e8b0..54da7db490 100644 --- a/best-practices/en/attribute-requires.texy +++ b/best-practices/en/attribute-requires.texy @@ -175,5 +175,3 @@ Conclusion ---------- The `#[Requires]` attribute gives you great flexibility and control over how your web pages are accessed. Using simple, yet powerful rules, you can enhance the security and proper functioning of your application. As you can see, using attributes in Nette can not only simplify your work but also secure it. - -{{sitename: Best Practices}} diff --git a/best-practices/en/composer.texy b/best-practices/en/composer.texy index dd972f2121..1e08a82668 100644 --- a/best-practices/en/composer.texy +++ b/best-practices/en/composer.texy @@ -280,5 +280,3 @@ Composer is closely integrated with the version control tool [Git |https://git-s ```shell composer -g config preferred-install dist ``` - -{{sitename: Best Practices}} diff --git a/best-practices/en/creating-editing-form.texy b/best-practices/en/creating-editing-form.texy index 6a76e2aeb0..86003dffc6 100644 --- a/best-practices/en/creating-editing-form.texy +++ b/best-practices/en/creating-editing-form.texy @@ -29,11 +29,11 @@ class RecordPresenter extends Nette\Application\UI\Presenter // ... add form fields ... - $form->onSuccess[] = [$this, 'recordFormSucceeded']; + $form->onSuccess[] = $this->recordFormSucceeded(...); return $form; } - public function recordFormSucceeded(Form $form, array $data): void + private function recordFormSucceeded(Form $form, array $data): void { $this->facade->add($data); // add record to the database $this->flashMessage('Successfully added'); @@ -91,11 +91,11 @@ class RecordPresenter extends Nette\Application\UI\Presenter // ... add form fields ... $form->setDefaults($this->record); // set default values - $form->onSuccess[] = [$this, 'recordFormSucceeded']; + $form->onSuccess[] = $this->recordFormSucceeded(...); return $form; } - public function recordFormSucceeded(Form $form, array $data): void + private function recordFormSucceeded(Form $form, array $data): void { $this->facade->update($this->record->id, $data); // update record $this->flashMessage('Successfully updated'); @@ -130,7 +130,6 @@ We store the record in the `$record` property, making it available in the `creat $this->facade->update($id, $data); // ... } -} ``` However, and this should be **the most important takeaway from the entire code**, we must ensure the action is indeed `edit` when creating the form. Otherwise, the verification in the `actionEdit()` method would not occur at all! @@ -153,7 +152,7 @@ class RecordPresenter extends Nette\Application\UI\Presenter public function actionAdd(): void { $form = $this->getComponent('recordForm'); - $form->onSuccess[] = [$this, 'addingFormSucceeded']; + $form->onSuccess[] = $this->addingFormSucceeded(...); } public function actionEdit(int $id): void @@ -168,7 +167,7 @@ class RecordPresenter extends Nette\Application\UI\Presenter $form = $this->getComponent('recordForm'); $form->setDefaults($record); // set default values - $form->onSuccess[] = [$this, 'editingFormSucceeded']; + $form->onSuccess[] = $this->editingFormSucceeded(...); } protected function createComponentRecordForm(): Form @@ -185,14 +184,14 @@ class RecordPresenter extends Nette\Application\UI\Presenter return $form; } - public function addingFormSucceeded(Form $form, array $data): void + private function addingFormSucceeded(Form $form, array $data): void { $this->facade->add($data); // add record to the database $this->flashMessage('Successfully added'); $this->redirect('...'); } - public function editingFormSucceeded(Form $form, array $data): void + private function editingFormSucceeded(Form $form, array $data): void { $id = (int) $this->getParameter('id'); $this->facade->update($id, $data); // update record @@ -203,4 +202,3 @@ class RecordPresenter extends Nette\Application\UI\Presenter ``` {{priority: -1}} -{{sitename: Best Practices}} diff --git a/best-practices/en/dynamic-snippets.texy b/best-practices/en/dynamic-snippets.texy index a9221516a9..144d00268a 100644 --- a/best-practices/en/dynamic-snippets.texy +++ b/best-practices/en/dynamic-snippets.texy @@ -171,4 +171,3 @@ The view's template shrinks to the bare minimum (and is completely free of snipp We're almost finished: the application will now function with AJAX. Here too, optimization is needed because, due to the use of Nette Database, signal processing unnecessarily loads all articles from the database instead of just the relevant one. The advantage, however, is that no unnecessary rendering occurs, as only the specific component instance is rendered. {{priority: -1}} -{{sitename: Best Practices}} diff --git a/best-practices/en/editors-and-tools.texy b/best-practices/en/editors-and-tools.texy index 48fe84f530..e81b575eb6 100644 --- a/best-practices/en/editors-and-tools.texy +++ b/best-practices/en/editors-and-tools.texy @@ -13,9 +13,9 @@ We strongly recommend using a full-featured IDE for development, like PhpStorm, **NetBeans IDE** has built-in support for Nette, Latte, and NEON. **PhpStorm**: Install these plugins via `Settings > Plugins > Marketplace`: -- Nette framework helpers -- Latte -- NEON support +- [Nette |https://plugins.jetbrains.com/plugin/28342-nette] +- [Latte |https://plugins.jetbrains.com/plugin/24218-latte-support] or [Latte Pro |https://plugins.jetbrains.com/plugin/19661-latte-pro] +- [NEON |https://plugins.jetbrains.com/plugin/28338-neon] or [NEON / Nette support |https://plugins.jetbrains.com/plugin/18387-neon-nette-support] - Nette Tester **VS Code**: Find the "Nette Latte + Neon" plugin in the marketplace. @@ -82,5 +82,3 @@ Requirements Checker ==================== This was a tool that tested the server's runtime environment and indicated whether (and to what extent) the framework could be used. Currently, Nette can be used on any server that meets the minimum required PHP version. - -{{sitename: Best Practices}} diff --git a/best-practices/en/form-reuse.texy b/best-practices/en/form-reuse.texy index 2924b3dd09..2d91c006fc 100644 --- a/best-practices/en/form-reuse.texy +++ b/best-practices/en/form-reuse.texy @@ -193,11 +193,11 @@ class EditFormFactory $form->addText('title', 'Title:'); // additional form fields are added here $form->addSubmit('send', 'Save'); - $form->onSuccess[] = [$this, 'processForm']; + $form->onSuccess[] = $this->processForm(...); return $form; } - public function processForm(Form $form, array $data): void + private function processForm(Form $form, array $data): void { try { // processing of submitted data @@ -284,12 +284,12 @@ class EditControl extends Nette\Application\UI\Control $form->addText('title', 'Title:'); // additional form fields are added here $form->addSubmit('send', 'Save'); - $form->onSuccess[] = [$this, 'processForm']; + $form->onSuccess[] = $this->processForm(...); return $form; } - public function processForm(Form $form, array $data): void + private function processForm(Form $form, array $data): void { try { // processing of submitted data @@ -346,5 +346,3 @@ class MyPresenter extends Nette\Application\UI\Presenter } } ``` - -{{sitename: Best Practices}} diff --git a/best-practices/en/inject-method-attribute.texy b/best-practices/en/inject-method-attribute.texy index a3db1098dc..b1c36d8df1 100644 --- a/best-practices/en/inject-method-attribute.texy +++ b/best-practices/en/inject-method-attribute.texy @@ -59,6 +59,3 @@ class MyPresenter extends Nette\Application\UI\Presenter The advantage of this dependency passing method was its very concise syntax. However, with the introduction of [constructor property promotion |https://blog.nette.org/en/php-8-0-complete-overview-of-news#toc-constructor-property-promotion], using the constructor often appears simpler. Conversely, this method suffers from the same drawbacks as property injection in general: we lack control over changes to the variable, and the variable becomes part of the class's public interface, which is generally undesirable. - - -{{sitename: Best Practices}} diff --git a/best-practices/en/lets-create-contact-form.texy b/best-practices/en/lets-create-contact-form.texy index 3f1c5f95fe..695985f569 100644 --- a/best-practices/en/lets-create-contact-form.texy +++ b/best-practices/en/lets-create-contact-form.texy @@ -24,11 +24,11 @@ class HomePresenter extends Presenter $form->addTextarea('message', 'Message:') ->setRequired('Please enter a message'); $form->addSubmit('send', 'Send'); - $form->onSuccess[] = [$this, 'contactFormSucceeded']; + $form->onSuccess[] = $this->contactFormSucceeded(...); return $form; } - public function contactFormSucceeded(Form $form, $data): void + private function contactFormSucceeded(Form $form, $data): void { // sending an email } @@ -48,9 +48,6 @@ Let's render the `contactForm` component in the `Home/default.latte` template: For sending the email itself, we'll create a new class named `ContactFacade` and place it in the file `app/Model/ContactFacade.php`: ```php -onSuccess[] = [$this, 'signInFormSubmitted']; + $form->onSuccess[] = $this->signInFormSubmitted(...); return $form; } - public function signInFormSubmitted($form) + private function signInFormSubmitted($form) { // ... log the user in here ... @@ -60,4 +60,3 @@ We pass the key (`$this->backlink`) of the stored request to the `restoreRequest However, if the key is invalid (e.g., it has expired from the session), the method does nothing. Therefore, the subsequent call `$this->redirect('Admin:')` acts as a fallback, redirecting to a default page like `AdminPresenter`. {{priority: -1}} -{{sitename: Best Practices}} diff --git a/best-practices/es/@home.texy b/best-practices/es/@home.texy index 7291597010..6a6ee9df47 100644 --- a/best-practices/es/@home.texy +++ b/best-practices/es/@home.texy @@ -67,6 +67,3 @@ Cientos de grabaciones de los Últimos Sábados y vídeos sobre Nette se pueden - -{{sitename: Best Practices}} -{{leftbar: www:@menu-common}} diff --git a/best-practices/es/@meta.texy b/best-practices/es/@meta.texy new file mode 100644 index 0000000000..524cb19ad0 --- /dev/null +++ b/best-practices/es/@meta.texy @@ -0,0 +1,2 @@ +{{sitename: Tutoriales y procedimientos}} +{{leftbar: www:@menu-common}} diff --git a/best-practices/es/attribute-requires.texy b/best-practices/es/attribute-requires.texy index bf04cca318..0eebe50721 100644 --- a/best-practices/es/attribute-requires.texy +++ b/best-practices/es/attribute-requires.texy @@ -175,5 +175,3 @@ Conclusión ---------- El atributo `#[Requires]` le da una gran flexibilidad y control sobre cómo son accesibles sus páginas web. Usando reglas simples pero potentes, puede aumentar la seguridad y el correcto funcionamiento de su aplicación. Como puede ver, el uso de atributos en Nette no solo puede facilitar su trabajo, sino también asegurarlo. - -{{sitename: Best Practices}} diff --git a/best-practices/es/composer.texy b/best-practices/es/composer.texy index eabb093dd9..20959bbc87 100644 --- a/best-practices/es/composer.texy +++ b/best-practices/es/composer.texy @@ -280,5 +280,3 @@ Composer está estrechamente vinculado con la herramienta de versionado [Git |ht ```shell composer -g config preferred-install dist ``` - -{{sitename: Best Practices}} diff --git a/best-practices/es/creating-editing-form.texy b/best-practices/es/creating-editing-form.texy index 58a6acaec9..9d44a9d52f 100644 --- a/best-practices/es/creating-editing-form.texy +++ b/best-practices/es/creating-editing-form.texy @@ -203,4 +203,3 @@ class RecordPresenter extends Nette\Application\UI\Presenter ``` {{priority: -1}} -{{sitename: Best Practices}} diff --git a/best-practices/es/dynamic-snippets.texy b/best-practices/es/dynamic-snippets.texy index 2b69e3afe9..37ca43eec5 100644 --- a/best-practices/es/dynamic-snippets.texy +++ b/best-practices/es/dynamic-snippets.texy @@ -171,4 +171,3 @@ La plantilla de la vista se reduce al mínimo indispensable (¡y completamente l Casi hemos terminado: la aplicación ahora funcionará con AJAX. Aquí también tendremos que optimizar la aplicación, porque debido al uso de Nette Database, al procesar la señal se cargan innecesariamente todos los artículos de la base de datos en lugar de uno solo. Sin embargo, la ventaja es que no se renderizarán, ya que realmente solo se renderizará nuestro componente. {{priority: -1}} -{{sitename: Best Practices}} diff --git a/best-practices/es/editors-and-tools.texy b/best-practices/es/editors-and-tools.texy index 3c8cd48632..36d9c62866 100644 --- a/best-practices/es/editors-and-tools.texy +++ b/best-practices/es/editors-and-tools.texy @@ -82,5 +82,3 @@ Requirements Checker ==================== Era una herramienta que probaba el entorno de ejecución del servidor e informaba si (y en qué medida) se podía utilizar el framework. Actualmente, Nette se puede utilizar en cualquier servidor que tenga la versión mínima requerida de PHP. - -{{sitename: Best Practices}} diff --git a/best-practices/es/form-reuse.texy b/best-practices/es/form-reuse.texy index dfc21839d3..3998002707 100644 --- a/best-practices/es/form-reuse.texy +++ b/best-practices/es/form-reuse.texy @@ -346,5 +346,3 @@ class MyPresenter extends Nette\Application\UI\Presenter } } ``` - -{{sitename: Best Practices}} diff --git a/best-practices/es/inject-method-attribute.texy b/best-practices/es/inject-method-attribute.texy index e21b9f45c4..c24c918236 100644 --- a/best-practices/es/inject-method-attribute.texy +++ b/best-practices/es/inject-method-attribute.texy @@ -59,6 +59,3 @@ class MyPresenter extends Nette\Application\UI\Presenter La ventaja de esta forma de pasar dependencias era una sintaxis muy concisa. Sin embargo, con la llegada de [constructor property promotion |https://blog.nette.org/es/php-8-0-complete-overview-of-news#toc-constructor-property-promotion], parece más fácil usar el constructor. Por el contrario, esta forma sufre las mismas deficiencias que pasar dependencias a propiedades en general: no tenemos control sobre los cambios en la variable y, al mismo tiempo, la variable se convierte en parte de la interfaz pública de la clase, lo cual no es deseable. - - -{{sitename: Best Practices}} diff --git a/best-practices/es/lets-create-contact-form.texy b/best-practices/es/lets-create-contact-form.texy index 75d68824d4..208b6174f5 100644 --- a/best-practices/es/lets-create-contact-form.texy +++ b/best-practices/es/lets-create-contact-form.texy @@ -219,6 +219,3 @@ parameters: ``` ¡Y listo! - - -{{sitename: Best Practices}} diff --git a/best-practices/es/microsites.texy b/best-practices/es/microsites.texy index 175ef361bf..392f299d5f 100644 --- a/best-practices/es/microsites.texy +++ b/best-practices/es/microsites.texy @@ -61,5 +61,3 @@ El código PHP en `index.php` primero [prepara el entorno |bootstrap:], luego de - A veces te puede resultar útil el [caching|caching:], por ejemplo, si descargas y muestras feeds. En la actualidad, donde la velocidad y la eficiencia son clave, es importante tener herramientas que te permitan lograr resultados sin demoras innecesarias. Nette framework te ofrece precisamente eso: desarrollo rápido, seguridad y una amplia gama de herramientas, como Tracy y Latte, que simplifican el proceso. Simplemente instala algunos paquetes de Nette y construir un micrositio así se convierte de repente en un juego de niños. Y sabes que no hay ninguna brecha de seguridad oculta en ninguna parte. - -{{sitename: Best Practices}} diff --git a/best-practices/es/pagination.texy b/best-practices/es/pagination.texy index 8874e3b595..13d443cbaf 100644 --- a/best-practices/es/pagination.texy +++ b/best-practices/es/pagination.texy @@ -271,4 +271,3 @@ Dado que ahora no enviamos Paginator a la plantilla, modificaremos la parte que De esta manera, hemos implementado el mecanismo de paginación sin usar Paginator. {{priority: -1}} -{{sitename: Best Practices}} diff --git a/best-practices/es/passing-settings-to-presenters.texy b/best-practices/es/passing-settings-to-presenters.texy index ae9e7018bd..a54e1ab5da 100644 --- a/best-practices/es/passing-settings-to-presenters.texy +++ b/best-practices/es/passing-settings-to-presenters.texy @@ -47,5 +47,3 @@ class MyPresenter extends Nette\Application\UI\Presenter } } ``` - -{{sitename: Best Practices}} diff --git a/best-practices/es/post-links.texy b/best-practices/es/post-links.texy index 74f40fbae6..8b0d2e0bab 100644 --- a/best-practices/es/post-links.texy +++ b/best-practices/es/post-links.texy @@ -54,6 +54,3 @@ public function handleDelete(int $id): void ``` Este enfoque no solo mejora la seguridad de tu aplicación, sino que también contribuye al cumplimiento de los estándares y prácticas web correctos. Al utilizar métodos POST para acciones que cambian el estado, lograrás una aplicación más robusta y segura. - - -{{sitename: Best Practices}} diff --git a/best-practices/es/presenter-traits.texy b/best-practices/es/presenter-traits.texy index c61482980a..b1dc7af72f 100644 --- a/best-practices/es/presenter-traits.texy +++ b/best-practices/es/presenter-traits.texy @@ -45,6 +45,3 @@ class ArticlePresenter extends Nette\Application\UI\Presenter use RequireLoggedUser; } ``` - - -{{sitename: Best Practices}} diff --git a/best-practices/es/restore-request.texy b/best-practices/es/restore-request.texy index 64439d3481..23de10d19f 100644 --- a/best-practices/es/restore-request.texy +++ b/best-practices/es/restore-request.texy @@ -60,4 +60,3 @@ Pasamos la clave de la solicitud guardada al método `restoreRequest()` y este r Sin embargo, si la clave no es válida (por ejemplo, ya no existe en la sesión), el método no hace nada. Por lo tanto, sigue la llamada `$this->redirect('Admin:')`, que redirige a `AdminPresenter`. {{priority: -1}} -{{sitename: Best Practices}} diff --git a/best-practices/fr/@home.texy b/best-practices/fr/@home.texy index d9f738390c..829741034c 100644 --- a/best-practices/fr/@home.texy +++ b/best-practices/fr/@home.texy @@ -67,6 +67,3 @@ Des centaines d'enregistrements des Derniers Samedis et de vidéos sur Nette peu - -{{sitename: Bonnes pratiques}} -{{leftbar: www:@menu-common}} diff --git a/best-practices/fr/@meta.texy b/best-practices/fr/@meta.texy new file mode 100644 index 0000000000..ae1deef2d5 --- /dev/null +++ b/best-practices/fr/@meta.texy @@ -0,0 +1,2 @@ +{{sitename: Tutoriels et bonnes pratiques}} +{{leftbar: www:@menu-common}} diff --git a/best-practices/fr/attribute-requires.texy b/best-practices/fr/attribute-requires.texy index b93b664e1f..afeb4699c6 100644 --- a/best-practices/fr/attribute-requires.texy +++ b/best-practices/fr/attribute-requires.texy @@ -175,5 +175,3 @@ Conclusion ---------- L'attribut `#[Requires]` vous offre une grande flexibilité et un contrôle sur la manière dont vos pages web sont accessibles. À l'aide de règles simples mais puissantes, vous pouvez augmenter la sécurité et le bon fonctionnement de votre application. Comme vous pouvez le voir, l'utilisation des attributs dans Nette peut non seulement faciliter votre travail, mais aussi le sécuriser. - -{{sitename: Best Practices}} diff --git a/best-practices/fr/composer.texy b/best-practices/fr/composer.texy index b1c9478902..b8f9a3e43b 100644 --- a/best-practices/fr/composer.texy +++ b/best-practices/fr/composer.texy @@ -280,5 +280,3 @@ Composer est étroitement lié à l'outil de versionnement [Git |https://git-scm ```shell composer -g config preferred-install dist ``` - -{{sitename: Best Practices}} diff --git a/best-practices/fr/creating-editing-form.texy b/best-practices/fr/creating-editing-form.texy index 572bd23b28..b05616ac5e 100644 --- a/best-practices/fr/creating-editing-form.texy +++ b/best-practices/fr/creating-editing-form.texy @@ -203,4 +203,3 @@ class RecordPresenter extends Nette\Application\UI\Presenter ``` {{priority: -1}} -{{sitename: Best Practices}} diff --git a/best-practices/fr/dynamic-snippets.texy b/best-practices/fr/dynamic-snippets.texy index 050ba47bc2..d285c2c138 100644 --- a/best-practices/fr/dynamic-snippets.texy +++ b/best-practices/fr/dynamic-snippets.texy @@ -171,4 +171,3 @@ Le template de la vue est réduit au minimum nécessaire (et totalement dépourv Nous avons presque terminé : l'application fonctionnera désormais en AJAX. Ici aussi, nous devons optimiser l'application, car en raison de l'utilisation de Nette Database, lors du traitement du signal, tous les articles sont inutilement chargés depuis la base de données au lieu d'un seul. L'avantage, cependant, est qu'ils ne seront pas rendus, car seul notre composant sera réellement rendu. {{priority: -1}} -{{sitename: Best Practices}} diff --git a/best-practices/fr/editors-and-tools.texy b/best-practices/fr/editors-and-tools.texy index 7714a82613..f80342f3fe 100644 --- a/best-practices/fr/editors-and-tools.texy +++ b/best-practices/fr/editors-and-tools.texy @@ -82,5 +82,3 @@ Requirements Checker ==================== C'était un outil qui testait l'environnement d'exécution du serveur et informait si (et dans quelle mesure) le framework pouvait être utilisé. Actuellement, Nette peut être utilisé sur n'importe quel serveur disposant de la version minimale requise de PHP. - -{{sitename: Best Practices}} diff --git a/best-practices/fr/form-reuse.texy b/best-practices/fr/form-reuse.texy index 59ed049764..234ff21ee0 100644 --- a/best-practices/fr/form-reuse.texy +++ b/best-practices/fr/form-reuse.texy @@ -346,5 +346,3 @@ class MyPresenter extends Nette\Application\UI\Presenter } } ``` - -{{sitename: Best Practices}} diff --git a/best-practices/fr/inject-method-attribute.texy b/best-practices/fr/inject-method-attribute.texy index 7697c7b644..a9896afe31 100644 --- a/best-practices/fr/inject-method-attribute.texy +++ b/best-practices/fr/inject-method-attribute.texy @@ -59,6 +59,3 @@ class MyPresenter extends Nette\Application\UI\Presenter L'avantage de cette méthode de transmission des dépendances était sa forme d'écriture très concise. Cependant, avec l'arrivée de la [promotion des propriétés du constructeur |https://blog.nette.org/fr/php-8-0-complete-overview-of-news#toc-constructor-property-promotion], il semble plus facile d'utiliser le constructeur. Inversement, cette méthode souffre des mêmes défauts que la transmission de dépendances aux propriétés en général : nous n'avons aucun contrôle sur les changements dans la variable, et en même temps, la variable devient partie intégrante de l'interface publique de la classe, ce qui n'est pas souhaitable. - - -{{sitename: Best Practices}} diff --git a/best-practices/fr/lets-create-contact-form.texy b/best-practices/fr/lets-create-contact-form.texy index dc14c131b3..081268c0b0 100644 --- a/best-practices/fr/lets-create-contact-form.texy +++ b/best-practices/fr/lets-create-contact-form.texy @@ -219,6 +219,3 @@ parameters: ``` Et c'est terminé ! - - -{{sitename: Best Practices}} diff --git a/best-practices/fr/microsites.texy b/best-practices/fr/microsites.texy index 370ae19aee..cf0410f4ed 100644 --- a/best-practices/fr/microsites.texy +++ b/best-practices/fr/microsites.texy @@ -61,5 +61,3 @@ Pourquoi utiliser Nette pour un microsite ? - Parfois, la [mise en cache|caching:] peut vous être utile, par exemple si vous téléchargez et affichez des flux. À notre époque, où la vitesse et l'efficacité sont essentielles, il est important de disposer d'outils qui vous permettent d'obtenir des résultats sans délai inutile. Le framework Nette vous offre exactement cela - un développement rapide, la sécurité et une large gamme d'outils, tels que Tracy et Latte, qui simplifient le processus. Il suffit d'installer quelques paquets Nette et construire un tel microsite devient soudain un jeu d'enfant. Et vous savez qu'aucune faille de sécurité ne se cache nulle part. - -{{sitename: Best Practices}} diff --git a/best-practices/fr/pagination.texy b/best-practices/fr/pagination.texy index 0a76ce5faf..4c008577ae 100644 --- a/best-practices/fr/pagination.texy +++ b/best-practices/fr/pagination.texy @@ -271,4 +271,3 @@ Comme nous n'envoyons plus de Paginator au template, nous modifions la partie af De cette manière, nous avons implémenté le mécanisme de pagination en utilisant la méthode `page()` de Nette Database Explorer. {{priority: -1}} -{{sitename: Best Practices}} diff --git a/best-practices/fr/passing-settings-to-presenters.texy b/best-practices/fr/passing-settings-to-presenters.texy index 13f0d121a7..3aeba172c5 100644 --- a/best-practices/fr/passing-settings-to-presenters.texy +++ b/best-practices/fr/passing-settings-to-presenters.texy @@ -47,5 +47,3 @@ class MyPresenter extends Nette\Application\UI\Presenter } } ``` - -{{sitename: Best Practices}} diff --git a/best-practices/fr/post-links.texy b/best-practices/fr/post-links.texy index 459ad9de7f..d4c098524f 100644 --- a/best-practices/fr/post-links.texy +++ b/best-practices/fr/post-links.texy @@ -54,6 +54,3 @@ public function handleDelete(int $id): void ``` Cette approche améliore non seulement la sécurité de votre application, mais contribue également au respect des normes et pratiques web correctes. En utilisant les méthodes POST pour les actions modifiant l'état, vous obtiendrez une application plus robuste et plus sûre. - - -{{sitename: Best Practices}} diff --git a/best-practices/fr/presenter-traits.texy b/best-practices/fr/presenter-traits.texy index 36e70f84ab..551c1d5368 100644 --- a/best-practices/fr/presenter-traits.texy +++ b/best-practices/fr/presenter-traits.texy @@ -45,6 +45,3 @@ class ArticlePresenter extends Nette\Application\UI\Presenter use RequireLoggedUser; } ``` - - -{{sitename: Best Practices}} diff --git a/best-practices/fr/restore-request.texy b/best-practices/fr/restore-request.texy index 1fbfb55a08..277e87d9ff 100644 --- a/best-practices/fr/restore-request.texy +++ b/best-practices/fr/restore-request.texy @@ -60,4 +60,3 @@ Nous passons la clé de la requête sauvegardée à la méthode `restoreRequest( Cependant, si la clé n'est pas valide (par exemple, elle n'existe plus dans la session), la méthode ne fait rien. L'appel `$this->redirect('Admin:')` suit donc, qui redirige vers `AdminPresenter`. {{priority: -1}} -{{sitename: Best Practices}} diff --git a/best-practices/hu/@home.texy b/best-practices/hu/@home.texy index f8e2a8e179..e1ab1cabd8 100644 --- a/best-practices/hu/@home.texy +++ b/best-practices/hu/@home.texy @@ -67,6 +67,3 @@ Több száz felvétel a Poslední sobota eseményekről és Nette videók egy he - -{{sitename: Best Practices}} -{{leftbar: www:@menu-common}} diff --git a/best-practices/hu/@meta.texy b/best-practices/hu/@meta.texy new file mode 100644 index 0000000000..9a70856e97 --- /dev/null +++ b/best-practices/hu/@meta.texy @@ -0,0 +1,2 @@ +{{sitename: Útmutatók és eljárások}} +{{leftbar: www:@menu-common}} diff --git a/best-practices/hu/attribute-requires.texy b/best-practices/hu/attribute-requires.texy index ff446a6ded..819f823943 100644 --- a/best-practices/hu/attribute-requires.texy +++ b/best-practices/hu/attribute-requires.texy @@ -175,5 +175,3 @@ Következtetés ------------- A `#[Requires]` attribútum nagy rugalmasságot és kontrollt ad Önnek afölött, hogyan érhetők el a weboldalai. Egyszerű, de erőteljes szabályok segítségével növelheti alkalmazása biztonságát és helyes működését. Mint láthatja, az attribútumok használata a Nette-ben nemcsak megkönnyítheti a munkáját, hanem biztonságosabbá is teheti. - -{{sitename: Best Practices}} diff --git a/best-practices/hu/composer.texy b/best-practices/hu/composer.texy index d9b58bc43d..97d7faa75c 100644 --- a/best-practices/hu/composer.texy +++ b/best-practices/hu/composer.texy @@ -280,5 +280,3 @@ A Composer szorosan kapcsolódik a [Git |https://git-scm.com] verziókezelő esz ```shell composer -g config preferred-install dist ``` - -{{sitename: Best Practices}} diff --git a/best-practices/hu/creating-editing-form.texy b/best-practices/hu/creating-editing-form.texy index 0530a75fac..959ed13a7b 100644 --- a/best-practices/hu/creating-editing-form.texy +++ b/best-practices/hu/creating-editing-form.texy @@ -203,4 +203,3 @@ class RecordPresenter extends Nette\Application\UI\Presenter ``` {{priority: -1}} -{{sitename: Best Practices}} diff --git a/best-practices/hu/dynamic-snippets.texy b/best-practices/hu/dynamic-snippets.texy index 5e847d364c..b6df024d32 100644 --- a/best-practices/hu/dynamic-snippets.texy +++ b/best-practices/hu/dynamic-snippets.texy @@ -171,4 +171,3 @@ A view sablonja a szükséges minimumra csökken (és teljesen mentes a snippett Majdnem készen vagyunk: az alkalmazás mostantól AJAX-osan fog működni. Itt is optimalizálnunk kell az alkalmazást, mert a Nette Database használata miatt a signál feldolgozásakor feleslegesen betöltődik az összes cikk az adatbázisból egy helyett. Előnye azonban, hogy nem kerülnek kirajzolásra, mert valóban csak a mi komponensünk renderelődik. {{priority: -1}} -{{sitename: Best Practices}} diff --git a/best-practices/hu/editors-and-tools.texy b/best-practices/hu/editors-and-tools.texy index 26e3bf7980..7104666da7 100644 --- a/best-practices/hu/editors-and-tools.texy +++ b/best-practices/hu/editors-and-tools.texy @@ -82,5 +82,3 @@ Requirements Checker ==================== Ez egy eszköz volt, amely tesztelte a szerver futási környezetét, és tájékoztatott arról, hogy (és milyen mértékben) lehet használni a keretrendszert. Jelenleg a Nette minden olyan szerveren használható, amely rendelkezik a minimálisan szükséges PHP verzióval. - -{{sitename: Best Practices}} diff --git a/best-practices/hu/form-reuse.texy b/best-practices/hu/form-reuse.texy index fad3d87058..cbda52b931 100644 --- a/best-practices/hu/form-reuse.texy +++ b/best-practices/hu/form-reuse.texy @@ -346,5 +346,3 @@ class MyPresenter extends Nette\Application\UI\Presenter } } ``` - -{{sitename: Best Practices}} diff --git a/best-practices/hu/inject-method-attribute.texy b/best-practices/hu/inject-method-attribute.texy index 7939b28085..f36ead2d52 100644 --- a/best-practices/hu/inject-method-attribute.texy +++ b/best-practices/hu/inject-method-attribute.texy @@ -59,6 +59,3 @@ class MyPresenter extends Nette\Application\UI\Presenter Ennek a függőségátadási módnak az előnye a nagyon tömör írásmód volt. Azonban a [constructor property promotion |https://blog.nette.org/hu/php-8-0-complete-overview-of-news#toc-constructor-property-promotion] megjelenésével egyszerűbbnek tűnik a konstruktor használata. Másrészt ez a módszer ugyanazoktól a hiányosságoktól szenved, mint a függőségek általános property-kbe történő átadása: nincs ellenőrzésünk a változóban bekövetkező változások felett, és ugyanakkor a változó az osztály nyilvános interfészének részévé válik, ami nem kívánatos. - - -{{sitename: Best Practices}} diff --git a/best-practices/hu/lets-create-contact-form.texy b/best-practices/hu/lets-create-contact-form.texy index 8e7c96a90e..3ceafb1f03 100644 --- a/best-practices/hu/lets-create-contact-form.texy +++ b/best-practices/hu/lets-create-contact-form.texy @@ -219,6 +219,3 @@ parameters: ``` És kész is vagyunk! - - -{{sitename: Best Practices}} diff --git a/best-practices/hu/microsites.texy b/best-practices/hu/microsites.texy index 5aecd10ab3..feb5f639bb 100644 --- a/best-practices/hu/microsites.texy +++ b/best-practices/hu/microsites.texy @@ -61,5 +61,3 @@ Miért használjunk Nette-t microsite-hoz? - Néha hasznos lehet a [gyorsítótárazás |caching:], például ha feedeket tölt le és jelenít meg. Napjainkban, amikor a sebesség és a hatékonyság kulcsfontosságú, fontos, hogy olyan eszközök álljanak rendelkezésre, amelyek lehetővé teszik az eredmények elérését felesleges késedelem nélkül. A Nette keretrendszer pontosan ezt kínálja - gyors fejlesztést, biztonságot és széles körű eszközöket, mint például a Tracy és a Latte, amelyek egyszerűsítik a folyamatot. Elég telepíteni néhány Nette csomagot, és egy ilyen microsite létrehozása hirtelen gyerekjáték. És tudja, hogy sehol sem rejtőzik biztonsági rés. - -{{sitename: Best Practices}} diff --git a/best-practices/hu/pagination.texy b/best-practices/hu/pagination.texy index 9b26b4f077..286a369a9b 100644 --- a/best-practices/hu/pagination.texy +++ b/best-practices/hu/pagination.texy @@ -271,4 +271,3 @@ Mivel most nem küldünk Paginatort a sablonba, módosítjuk a lapozó linkeket Ezzel a módszerrel implementáltuk a lapozó mechanizmust Paginator használata nélkül. {{priority: -1}} -{{sitename: Best Practices}} diff --git a/best-practices/hu/passing-settings-to-presenters.texy b/best-practices/hu/passing-settings-to-presenters.texy index 3ea0c37194..077d860afd 100644 --- a/best-practices/hu/passing-settings-to-presenters.texy +++ b/best-practices/hu/passing-settings-to-presenters.texy @@ -47,5 +47,3 @@ class MyPresenter extends Nette\Application\UI\Presenter } } ``` - -{{sitename: Best Practices}} diff --git a/best-practices/hu/post-links.texy b/best-practices/hu/post-links.texy index 011c978da5..8faa625780 100644 --- a/best-practices/hu/post-links.texy +++ b/best-practices/hu/post-links.texy @@ -54,6 +54,3 @@ public function handleDelete(int $id): void ``` Ez a megközelítés nemcsak javítja az alkalmazás biztonságát, hanem hozzájárul a helyes webes szabványok és gyakorlatok betartásához is. A POST metódusok használatával az állapotot megváltoztató műveletekhez robusztusabb és biztonságosabb alkalmazást érhet el. - - -{{sitename: Best Practices}} diff --git a/best-practices/hu/presenter-traits.texy b/best-practices/hu/presenter-traits.texy index decf8f1ca9..a8ec3c6482 100644 --- a/best-practices/hu/presenter-traits.texy +++ b/best-practices/hu/presenter-traits.texy @@ -45,6 +45,3 @@ class ArticlePresenter extends Nette\Application\UI\Presenter use RequireLoggedUser; } ``` - - -{{sitename: Best Practices}} diff --git a/best-practices/hu/restore-request.texy b/best-practices/hu/restore-request.texy index 4140a92656..9de22622f4 100644 --- a/best-practices/hu/restore-request.texy +++ b/best-practices/hu/restore-request.texy @@ -60,4 +60,3 @@ A `restoreRequest()` metódusnak átadjuk a mentett kérés kulcsát, és az át Ha azonban a kulcs érvénytelen (például már nem létezik a sessionben), a metódus nem tesz semmit. Ezt követi a `$this->redirect('Admin:')` hívása, amely átirányít az `AdminPresenter`-re. {{priority: -1}} -{{sitename: Best Practices}} diff --git a/best-practices/it/@home.texy b/best-practices/it/@home.texy index 9b06375639..7a11feda65 100644 --- a/best-practices/it/@home.texy +++ b/best-practices/it/@home.texy @@ -67,6 +67,3 @@ Centinaia di registrazioni dagli Ultimi Sabati e video su Nette si trovano sotto - -{{sitename: Best Practices}} -{{leftbar: www:@menu-common}} diff --git a/best-practices/it/@meta.texy b/best-practices/it/@meta.texy new file mode 100644 index 0000000000..6cd5c59394 --- /dev/null +++ b/best-practices/it/@meta.texy @@ -0,0 +1,2 @@ +{{sitename: Guide e procedure}} +{{leftbar: www:@menu-common}} diff --git a/best-practices/it/attribute-requires.texy b/best-practices/it/attribute-requires.texy index 6143fe9fde..a2d48132d6 100644 --- a/best-practices/it/attribute-requires.texy +++ b/best-practices/it/attribute-requires.texy @@ -175,5 +175,3 @@ Conclusione ----------- L'attributo `#[Requires]` ti offre grande flessibilità e controllo su come sono accessibili le tue pagine web. Utilizzando regole semplici ma potenti, puoi aumentare la sicurezza e il corretto funzionamento della tua applicazione. Come vedi, l'uso degli attributi in Nette può non solo facilitare il tuo lavoro, ma anche renderlo più sicuro. - -{{sitename: Best Practices}} diff --git a/best-practices/it/composer.texy b/best-practices/it/composer.texy index 4335ab8471..8eb011319e 100644 --- a/best-practices/it/composer.texy +++ b/best-practices/it/composer.texy @@ -280,5 +280,3 @@ Composer è strettamente legato allo strumento di versioning [Git |https://git-s ```shell composer -g config preferred-install dist ``` - -{{sitename: Best Practices}} diff --git a/best-practices/it/creating-editing-form.texy b/best-practices/it/creating-editing-form.texy index e4a187d491..7a5868873c 100644 --- a/best-practices/it/creating-editing-form.texy +++ b/best-practices/it/creating-editing-form.texy @@ -203,4 +203,3 @@ class RecordPresenter extends Nette\Application\UI\Presenter ``` {{priority: -1}} -{{sitename: Best Practices}} diff --git a/best-practices/it/dynamic-snippets.texy b/best-practices/it/dynamic-snippets.texy index daaa6ab6e9..e2c34a8080 100644 --- a/best-practices/it/dynamic-snippets.texy +++ b/best-practices/it/dynamic-snippets.texy @@ -171,4 +171,3 @@ Il template della vista si riduce al minimo indispensabile (e completamente priv Abbiamo quasi finito: l'applicazione ora funzionerà in modo AJAX. Anche qui dovremo ottimizzare l'applicazione, perché a causa dell'uso di Nette Database, durante l'elaborazione del segnale vengono caricati inutilmente tutti gli articoli dal database invece di uno solo. Il vantaggio, tuttavia, è che non verranno renderizzati, perché verrà renderizzato effettivamente solo il nostro componente. {{priority: -1}} -{{sitename: Best Practices}} diff --git a/best-practices/it/editors-and-tools.texy b/best-practices/it/editors-and-tools.texy index 2e7f9c57b2..9386b93f8e 100644 --- a/best-practices/it/editors-and-tools.texy +++ b/best-practices/it/editors-and-tools.texy @@ -82,5 +82,3 @@ Requirements Checker ==================== Era uno strumento che testava l'ambiente di runtime del server e informava se (e in che misura) fosse possibile utilizzare il framework. Attualmente, Nette può essere utilizzato su qualsiasi server che abbia la versione minima richiesta di PHP. - -{{sitename: Best Practices}} diff --git a/best-practices/it/form-reuse.texy b/best-practices/it/form-reuse.texy index f277f02e24..ccd4423502 100644 --- a/best-practices/it/form-reuse.texy +++ b/best-practices/it/form-reuse.texy @@ -346,5 +346,3 @@ class MyPresenter extends Nette\Application\UI\Presenter } } ``` - -{{sitename: Best Practices}} diff --git a/best-practices/it/inject-method-attribute.texy b/best-practices/it/inject-method-attribute.texy index 28a15600fc..d031886e4c 100644 --- a/best-practices/it/inject-method-attribute.texy +++ b/best-practices/it/inject-method-attribute.texy @@ -59,6 +59,3 @@ class MyPresenter extends Nette\Application\UI\Presenter Il vantaggio di questo modo di passare le dipendenze era la forma di scrittura molto concisa. Tuttavia, con l'avvento della [constructor property promotion |https://blog.nette.org/it/php-8-0-complete-overview-of-news#toc-constructor-property-promotion], sembra più facile utilizzare il costruttore. Al contrario, questo metodo soffre degli stessi svantaggi del passaggio delle dipendenze alle proprietà in generale: non abbiamo controllo sulle modifiche nella variabile e allo stesso tempo la variabile diventa parte dell'interfaccia pubblica della classe, il che è indesiderabile. - - -{{sitename: Best Practices}} diff --git a/best-practices/it/lets-create-contact-form.texy b/best-practices/it/lets-create-contact-form.texy index 2375125052..5b7992de4b 100644 --- a/best-practices/it/lets-create-contact-form.texy +++ b/best-practices/it/lets-create-contact-form.texy @@ -219,6 +219,3 @@ parameters: ``` Ed è fatto! - - -{{sitename: Best Practices}} diff --git a/best-practices/it/microsites.texy b/best-practices/it/microsites.texy index f53450bef6..1efd628d35 100644 --- a/best-practices/it/microsites.texy +++ b/best-practices/it/microsites.texy @@ -61,5 +61,3 @@ Perché usare Nette per un microsito? - A volte potrebbe esservi utile il [caching|caching:], ad esempio se scaricate e visualizzate feed. Al giorno d'oggi, quando la velocità e l'efficienza sono fondamentali, è importante avere strumenti che vi permettano di ottenere risultati senza inutili ritardi. Nette framework vi offre proprio questo: sviluppo rapido, sicurezza e un'ampia gamma di strumenti, come Tracy e Latte, che semplificano il processo. Basta installare un paio di pacchetti Nette e costruire un tale microsito diventa improvvisamente un gioco da ragazzi. E sapete che non si nasconde nessuna falla di sicurezza da nessuna parte. - -{{sitename: Best Practices}} diff --git a/best-practices/it/pagination.texy b/best-practices/it/pagination.texy index 14015254bc..1f61f6b633 100644 --- a/best-practices/it/pagination.texy +++ b/best-practices/it/pagination.texy @@ -271,4 +271,3 @@ Poiché ora non inviamo Paginator al template, modifichiamo la parte che visuali In questo modo abbiamo implementato il meccanismo di paginazione senza l'uso di Paginator. {{priority: -1}} -{{sitename: Best Practices}} diff --git a/best-practices/it/passing-settings-to-presenters.texy b/best-practices/it/passing-settings-to-presenters.texy index 71706b7fc5..61357ccd6b 100644 --- a/best-practices/it/passing-settings-to-presenters.texy +++ b/best-practices/it/passing-settings-to-presenters.texy @@ -47,5 +47,3 @@ class MyPresenter extends Nette\Application\UI\Presenter } } ``` - -{{sitename: Best Practices}} diff --git a/best-practices/it/post-links.texy b/best-practices/it/post-links.texy index 90036d98d7..7eccd96552 100644 --- a/best-practices/it/post-links.texy +++ b/best-practices/it/post-links.texy @@ -54,6 +54,3 @@ public function handleDelete(int $id): void ``` Questo approccio non solo migliora la sicurezza della vostra applicazione, ma contribuisce anche al rispetto degli standard e delle pratiche web corrette. Utilizzando i metodi POST per le azioni che modificano lo stato, otterrete un'applicazione più robusta e sicura. - - -{{sitename: Best Practices}} diff --git a/best-practices/it/presenter-traits.texy b/best-practices/it/presenter-traits.texy index da2b2d0e07..9fa07a6483 100644 --- a/best-practices/it/presenter-traits.texy +++ b/best-practices/it/presenter-traits.texy @@ -45,6 +45,3 @@ class ArticlePresenter extends Nette\Application\UI\Presenter use RequireLoggedUser; } ``` - - -{{sitename: Best Practices}} diff --git a/best-practices/it/restore-request.texy b/best-practices/it/restore-request.texy index 54062ba823..abb5ee93e8 100644 --- a/best-practices/it/restore-request.texy +++ b/best-practices/it/restore-request.texy @@ -60,4 +60,3 @@ Al metodo `restoreRequest()` passiamo la chiave della richiesta salvata e questo Tuttavia, se la chiave non è valida (ad esempio, non esiste più nella sessione), il metodo non fa nulla. Segue quindi la chiamata `$this->redirect('Admin:')`, che reindirizza a `AdminPresenter`. {{priority: -1}} -{{sitename: Best Practices}} diff --git a/best-practices/ja/@home.texy b/best-practices/ja/@home.texy index f7ac5de5b3..eab0e604fe 100644 --- a/best-practices/ja/@home.texy +++ b/best-practices/ja/@home.texy @@ -67,6 +67,3 @@ Poslední soboty の何百もの録画と Nette に関するビデオは、「Ne - -{{sitename: Best Practices}} -{{leftbar: www:@menu-common}} diff --git a/best-practices/ja/@meta.texy b/best-practices/ja/@meta.texy new file mode 100644 index 0000000000..faa40c5409 --- /dev/null +++ b/best-practices/ja/@meta.texy @@ -0,0 +1,2 @@ +{{sitename: ガイドとベストプラクティス}} +{{leftbar: www:@menu-common}} diff --git a/best-practices/ja/attribute-requires.texy b/best-practices/ja/attribute-requires.texy index 8825e3110a..5e374df7a0 100644 --- a/best-practices/ja/attribute-requires.texy +++ b/best-practices/ja/attribute-requires.texy @@ -175,5 +175,3 @@ class ApiPresenter extends Nette\Application\UI\Presenter --- `#[Requires]` 属性は、Web サイトへのアクセス方法について大きな柔軟性とコントロールを提供します。シンプルでありながら強力なルールを使用して、アプリケーションのセキュリティと適切な動作を向上させることができます。ご覧のとおり、Nette で属性を使用すると、作業が容易になるだけでなく、安全にもなります。 - -{{sitename: Best Practices}} diff --git a/best-practices/ja/composer.texy b/best-practices/ja/composer.texy index 286fcd49f1..afd0df7f16 100644 --- a/best-practices/ja/composer.texy +++ b/best-practices/ja/composer.texy @@ -280,5 +280,3 @@ Composerはバージョン管理ツール [Git |https://git-scm.com] と密接 ```shell composer -g config preferred-install dist ``` - -{{sitename: ベストプラクティス}} diff --git a/best-practices/ja/creating-editing-form.texy b/best-practices/ja/creating-editing-form.texy index a4176f8136..806cea4a84 100644 --- a/best-practices/ja/creating-editing-form.texy +++ b/best-practices/ja/creating-editing-form.texy @@ -203,4 +203,3 @@ class RecordPresenter extends Nette\Application\UI\Presenter ``` {{priority: -1}} -{{sitename: ベストプラクティス}} diff --git a/best-practices/ja/dynamic-snippets.texy b/best-practices/ja/dynamic-snippets.texy index edb6c61c47..eae6f47e34 100644 --- a/best-practices/ja/dynamic-snippets.texy +++ b/best-practices/ja/dynamic-snippets.texy @@ -171,4 +171,3 @@ protected function createComponentLikeControl() ほぼ完了です:アプリケーションはこれでAJAXで動作します。ここでもアプリケーションを最適化する必要があります。なぜなら、Nette Databaseを使用しているため、シグナルの処理中にデータベースから1つではなく、すべての記事が不必要にロードされるからです。しかし、利点は、実際に私たちのコンポーネントだけがレンダリングされるため、それらの描画が行われないことです。 {{priority: -1}} -{{sitename: ベストプラクティス}} diff --git a/best-practices/ja/editors-and-tools.texy b/best-practices/ja/editors-and-tools.texy index a839358bd8..36e72f6ea2 100644 --- a/best-practices/ja/editors-and-tools.texy +++ b/best-practices/ja/editors-and-tools.texy @@ -82,5 +82,3 @@ Requirements Checker ==================== これは、サーバーの実行環境をテストし、フレームワークを使用できるかどうか(およびどの程度まで)を通知するツールでした。現在、Netteは最小限必要なPHPバージョンを持つすべてのサーバーで使用できます。 - -{{sitename: ベストプラクティス}} diff --git a/best-practices/ja/form-reuse.texy b/best-practices/ja/form-reuse.texy index 7b2562bb8f..ed1fa5507b 100644 --- a/best-practices/ja/form-reuse.texy +++ b/best-practices/ja/form-reuse.texy @@ -346,5 +346,3 @@ class MyPresenter extends Nette\Application\UI\Presenter } } ``` - -{{sitename: ベストプラクティス}} diff --git a/best-practices/ja/inject-method-attribute.texy b/best-practices/ja/inject-method-attribute.texy index 66d01a14a1..7e85e1e486 100644 --- a/best-practices/ja/inject-method-attribute.texy +++ b/best-practices/ja/inject-method-attribute.texy @@ -59,6 +59,3 @@ class MyPresenter extends Nette\Application\UI\Presenter この依存関係の受け渡し方法の利点は、非常に簡潔な記述形式でした。しかし、[コンストラクタプロパティプロモーション |https://blog.nette.org/ja/php-8-0-new-features-overview#toc-constructor-property-promotion] の登場により、コンストラクタを使用する方が簡単に見えます。 逆に、この方法は、一般的にプロパティへの依存関係の受け渡しと同じ欠点があります:変数内の変更を制御できず、同時に変数がクラスのパブリックインターフェースの一部となり、これは望ましくありません。 - - -{{sitename: ベストプラクティス}} diff --git a/best-practices/ja/lets-create-contact-form.texy b/best-practices/ja/lets-create-contact-form.texy index a342052a76..e810ca3a2b 100644 --- a/best-practices/ja/lets-create-contact-form.texy +++ b/best-practices/ja/lets-create-contact-form.texy @@ -219,6 +219,3 @@ parameters: ``` これで完了です! - - -{{sitename: ベストプラクティス}} diff --git a/best-practices/ja/microsites.texy b/best-practices/ja/microsites.texy index 0c11688bc0..f534524da8 100644 --- a/best-practices/ja/microsites.texy +++ b/best-practices/ja/microsites.texy @@ -61,5 +61,3 @@ $container->getByType(Nette\Application\Application::class)->run(); - たとえばフィードを取得して表示する場合など、[キャッシュ|caching:] が役立つことがあります。 速度と効率が鍵となる今日の世界では、不必要な遅延なしに結果を達成できるツールを持つことが重要です。Nette frameworkはまさにそれを提供します - 迅速な開発、セキュリティ、そしてプロセスを簡素化するTracyやLatteなどの幅広いツール。いくつかのNetteパッケージをインストールするだけで、このようなマイクロサイトを構築するのは突然非常に簡単になります。そして、どこにもセキュリティホールが隠れていないことを知っています。 - -{{sitename: Best Practices}} diff --git a/best-practices/ja/pagination.texy b/best-practices/ja/pagination.texy index 7edca052f3..c2524004bd 100644 --- a/best-practices/ja/pagination.texy +++ b/best-practices/ja/pagination.texy @@ -271,4 +271,3 @@ class HomePresenter extends Nette\Application\UI\Presenter この方法で、Paginatorを使用せずにページネーションメカニズムを実装しました。 {{priority: -1}} -{{sitename: ベストプラクティス}} diff --git a/best-practices/ja/passing-settings-to-presenters.texy b/best-practices/ja/passing-settings-to-presenters.texy index 208ec25aa8..78fcc70158 100644 --- a/best-practices/ja/passing-settings-to-presenters.texy +++ b/best-practices/ja/passing-settings-to-presenters.texy @@ -47,5 +47,3 @@ class MyPresenter extends Nette\Application\UI\Presenter } } ``` - -{{sitename: ベストプラクティス}} diff --git a/best-practices/ja/post-links.texy b/best-practices/ja/post-links.texy index a1be3374f0..2d4877f097 100644 --- a/best-practices/ja/post-links.texy +++ b/best-practices/ja/post-links.texy @@ -54,6 +54,3 @@ public function handleDelete(int $id): void ``` このアプローチは、アプリケーションのセキュリティを向上させるだけでなく、正しいWeb標準と実践の遵守にも貢献します。状態を変更するアクションにPOSTメソッドを利用することで、より堅牢で安全なアプリケーションを実現できます。 - - -{{sitename: ベストプラクティス}} diff --git a/best-practices/ja/presenter-traits.texy b/best-practices/ja/presenter-traits.texy index ccaf3711c4..3410b8424f 100644 --- a/best-practices/ja/presenter-traits.texy +++ b/best-practices/ja/presenter-traits.texy @@ -45,6 +45,3 @@ class ArticlePresenter extends Nette\Application\UI\Presenter use RequireLoggedUser; } ``` - - -{{sitename: ベストプラクティス}} diff --git a/best-practices/ja/restore-request.texy b/best-practices/ja/restore-request.texy index 4ae6811f06..6a17b77503 100644 --- a/best-practices/ja/restore-request.texy +++ b/best-practices/ja/restore-request.texy @@ -60,4 +60,3 @@ class SignPresenter extends Nette\Application\UI\Presenter ただし、キーが無効な場合(たとえば、セッションに存在しなくなった場合)、メソッドは何も行いません。したがって、`AdminPresenter` にリダイレクトする `$this->redirect('Admin:')` の呼び出しが続きます。 {{priority: -1}} -{{sitename: ベストプラクティス}} diff --git a/best-practices/pl/@home.texy b/best-practices/pl/@home.texy index 825d540412..64470576e1 100644 --- a/best-practices/pl/@home.texy +++ b/best-practices/pl/@home.texy @@ -67,6 +67,3 @@ Setki nagrań z Posledních sobot i filmów o Nette znajdziesz pod jednym dachem - -{{sitename: Dobre praktyki}} -{{leftbar: www:@menu-common}} diff --git a/best-practices/pl/@meta.texy b/best-practices/pl/@meta.texy new file mode 100644 index 0000000000..28fbec9e34 --- /dev/null +++ b/best-practices/pl/@meta.texy @@ -0,0 +1,2 @@ +{{sitename: Przewodniki i dobre praktyki}} +{{leftbar: www:@menu-common}} diff --git a/best-practices/pl/attribute-requires.texy b/best-practices/pl/attribute-requires.texy index 515bf68c11..750a41a034 100644 --- a/best-practices/pl/attribute-requires.texy +++ b/best-practices/pl/attribute-requires.texy @@ -175,5 +175,3 @@ Zakończenie ----------- Atrybut `#[Requires]` daje Ci dużą elastyczność i kontrolę nad tym, jak dostępne są Twoje strony internetowe. Za pomocą prostych, ale potężnych reguł możesz zwiększyć bezpieczeństwo i prawidłowe funkcjonowanie Twojej aplikacji. Jak widzisz, użycie atrybutów w Nette może Twoją pracę nie tylko ułatwić, ale i zabezpieczyć. - -{{sitename: Best Practices}} diff --git a/best-practices/pl/composer.texy b/best-practices/pl/composer.texy index f9dbf766ee..f8ccf099f8 100644 --- a/best-practices/pl/composer.texy +++ b/best-practices/pl/composer.texy @@ -280,5 +280,3 @@ Composer jest ściśle powiązany z narzędziem do wersjonowania [Git |https://g ```shell composer -g config preferred-install dist ``` - -{{sitename: Best Practices}} diff --git a/best-practices/pl/creating-editing-form.texy b/best-practices/pl/creating-editing-form.texy index cf84a444b2..d5aeaa3c1c 100644 --- a/best-practices/pl/creating-editing-form.texy +++ b/best-practices/pl/creating-editing-form.texy @@ -203,4 +203,3 @@ class RecordPresenter extends Nette\Application\UI\Presenter ``` {{priority: -1}} -{{sitename: Best Practices}} diff --git a/best-practices/pl/dynamic-snippets.texy b/best-practices/pl/dynamic-snippets.texy index db88b1316a..67ac6ba7c0 100644 --- a/best-practices/pl/dynamic-snippets.texy +++ b/best-practices/pl/dynamic-snippets.texy @@ -171,4 +171,3 @@ Szablon widoku zmniejszy się do niezbędnego minimum (i całkowicie pozbawiony Mamy prawie gotowe: aplikacja teraz będzie działać AJAXowo. Również tutaj czeka nas optymalizacja aplikacji, ponieważ ze względu na użycie Nette Database podczas przetwarzania sygnału niepotrzebnie ładowane są wszystkie artykuły z bazy danych zamiast jednego. Zaletą jest jednak to, że nie dojdzie do ich renderowania, ponieważ wyrenderuje się rzeczywiście tylko nasz komponent. {{priority: -1}} -{{sitename: Best Practices}} diff --git a/best-practices/pl/editors-and-tools.texy b/best-practices/pl/editors-and-tools.texy index 26b4ed4286..7488231779 100644 --- a/best-practices/pl/editors-and-tools.texy +++ b/best-practices/pl/editors-and-tools.texy @@ -82,5 +82,3 @@ Requirements Checker ==================== Było to narzędzie, które testowało środowisko uruchomieniowe serwera i informowało, czy (i w jakim stopniu) można używać frameworka. Obecnie Nette można używać na każdym serwerze, który ma minimalną wymaganą wersję PHP. - -{{sitename: Best Practices}} diff --git a/best-practices/pl/form-reuse.texy b/best-practices/pl/form-reuse.texy index 7a65265c1d..c4b5179419 100644 --- a/best-practices/pl/form-reuse.texy +++ b/best-practices/pl/form-reuse.texy @@ -346,5 +346,3 @@ class MyPresenter extends Nette\Application\UI\Presenter } } ``` - -{{sitename: Best Practices}} diff --git a/best-practices/pl/inject-method-attribute.texy b/best-practices/pl/inject-method-attribute.texy index 3c4c88ec33..a5889d2155 100644 --- a/best-practices/pl/inject-method-attribute.texy +++ b/best-practices/pl/inject-method-attribute.texy @@ -59,6 +59,3 @@ class MyPresenter extends Nette\Application\UI\Presenter Zaletą tego sposobu przekazywania zależności była bardzo oszczędna forma zapisu. Jednak wraz z pojawieniem się [constructor property promotion |https://blog.nette.org/pl/php-8-0-complete-overview-of-news#toc-constructor-property-promotion] wydaje się łatwiejsze użycie konstruktora. Z drugiej strony, ten sposób cierpi na te same wady, co przekazywanie zależności do właściwości ogólnie: nie mamy kontroli nad zmianami w zmiennej, a jednocześnie zmienna staje się częścią publicznego interfejsu klasy, co jest niepożądane. - - -{{sitename: Best Practices}} diff --git a/best-practices/pl/lets-create-contact-form.texy b/best-practices/pl/lets-create-contact-form.texy index 6f8c5a43ef..4381796a10 100644 --- a/best-practices/pl/lets-create-contact-form.texy +++ b/best-practices/pl/lets-create-contact-form.texy @@ -219,6 +219,3 @@ parameters: ``` I gotowe! - - -{{sitename: Best Practices}} diff --git a/best-practices/pl/microsites.texy b/best-practices/pl/microsites.texy index 332bef3ec8..72b1666dae 100644 --- a/best-practices/pl/microsites.texy +++ b/best-practices/pl/microsites.texy @@ -61,5 +61,3 @@ Dlaczego używać Nette do mikrostroń? - Czasami może przydać się [cache|caching:], na przykład jeśli pobierasz i wyświetlasz feedy. W dzisiejszych czasach, gdy szybkość i efektywność są kluczowe, ważne jest posiadanie narzędzi, które pozwolą Ci osiągnąć wyniki bez zbędnego opóźnienia. Nette framework oferuje właśnie to - szybki rozwój, bezpieczeństwo i szeroką gamę narzędzi, takich jak Tracy i Latte, które upraszczają proces. Wystarczy zainstalować kilka pakietów Nette, a zbudowanie takiej mikrostroń staje się nagle dziecinnie proste. I wiesz, że nigdzie nie kryje się żadna dziura bezpieczeństwa. - -{{sitename: Best Practices}} diff --git a/best-practices/pl/pagination.texy b/best-practices/pl/pagination.texy index 44ca51c7d2..b79dc18dce 100644 --- a/best-practices/pl/pagination.texy +++ b/best-practices/pl/pagination.texy @@ -271,4 +271,3 @@ Ponieważ do szablonu teraz nie wysyłamy obiektu Paginator, zmodyfikujemy czę W ten sposób zaimplementowaliśmy mechanizm paginacji bez użycia Paginatora. {{priority: -1}} -{{sitename: Best Practices}} diff --git a/best-practices/pl/passing-settings-to-presenters.texy b/best-practices/pl/passing-settings-to-presenters.texy index 73f093dd82..2c8ef4b1f7 100644 --- a/best-practices/pl/passing-settings-to-presenters.texy +++ b/best-practices/pl/passing-settings-to-presenters.texy @@ -47,5 +47,3 @@ class MyPresenter extends Nette\Application\UI\Presenter } } ``` - -{{sitename: Best Practices}} diff --git a/best-practices/pl/post-links.texy b/best-practices/pl/post-links.texy index 004ed6747e..257edf12d6 100644 --- a/best-practices/pl/post-links.texy +++ b/best-practices/pl/post-links.texy @@ -54,6 +54,3 @@ public function handleDelete(int $id): void ``` Takie podejście nie tylko poprawia bezpieczeństwo Twojej aplikacji, ale także przyczynia się do przestrzegania prawidłowych standardów i praktyk internetowych. Wykorzystując metody POST do akcji zmieniających stan, osiągniesz bardziej solidną i bezpieczniejszą aplikację. - - -{{sitename: Best Practices}} diff --git a/best-practices/pl/presenter-traits.texy b/best-practices/pl/presenter-traits.texy index 3731b2f7ff..d819871207 100644 --- a/best-practices/pl/presenter-traits.texy +++ b/best-practices/pl/presenter-traits.texy @@ -45,6 +45,3 @@ class ArticlePresenter extends Nette\Application\UI\Presenter use RequireLoggedUser; } ``` - - -{{sitename: Best Practices}} diff --git a/best-practices/pl/restore-request.texy b/best-practices/pl/restore-request.texy index 47455b6c85..4d279ee9bb 100644 --- a/best-practices/pl/restore-request.texy +++ b/best-practices/pl/restore-request.texy @@ -60,4 +60,3 @@ Metodzie `restoreRequest()` przekazujemy klucz zapisanego żądania, a ona przek Jeśli jednak klucz jest nieprawidłowy (na przykład już nie istnieje w sesji), metoda nic nie robi. Następuje więc wywołanie `$this->redirect('Admin:')`, które przekierowuje na `AdminPresenter`. {{priority: -1}} -{{sitename: Best Practices}} diff --git a/best-practices/pt/@home.texy b/best-practices/pt/@home.texy index 79691787b7..ff77ce2b7f 100644 --- a/best-practices/pt/@home.texy +++ b/best-practices/pt/@home.texy @@ -67,6 +67,3 @@ Centenas de gravações dos Últimos Sábados e vídeos sobre Nette podem ser en - -{{sitename: Melhores Práticas}} -{{leftbar: www:@menu-common}} diff --git a/best-practices/pt/@meta.texy b/best-practices/pt/@meta.texy new file mode 100644 index 0000000000..1bf3200c6f --- /dev/null +++ b/best-practices/pt/@meta.texy @@ -0,0 +1,2 @@ +{{sitename: Guias e melhores práticas}} +{{leftbar: www:@menu-common}} diff --git a/best-practices/pt/attribute-requires.texy b/best-practices/pt/attribute-requires.texy index 8b0ba39018..e128fa61b9 100644 --- a/best-practices/pt/attribute-requires.texy +++ b/best-practices/pt/attribute-requires.texy @@ -175,5 +175,3 @@ Conclusão --------- O atributo `#[Requires]` oferece grande flexibilidade e controle sobre como suas páginas web são acessíveis. Usando regras simples, mas poderosas, você pode aumentar a segurança e o funcionamento correto da sua aplicação. Como você pode ver, o uso de atributos no Nette pode não apenas facilitar seu trabalho, mas também torná-lo mais seguro. - -{{sitename: Best Practices}} diff --git a/best-practices/pt/composer.texy b/best-practices/pt/composer.texy index 39f288c7b9..0bbb245278 100644 --- a/best-practices/pt/composer.texy +++ b/best-practices/pt/composer.texy @@ -280,5 +280,3 @@ O Composer está intimamente ligado à ferramenta de versionamento [Git |https:/ ```shell composer -g config preferred-install dist ``` - -{{sitename: Best Practices}} diff --git a/best-practices/pt/creating-editing-form.texy b/best-practices/pt/creating-editing-form.texy index ca47894989..c08c92a039 100644 --- a/best-practices/pt/creating-editing-form.texy +++ b/best-practices/pt/creating-editing-form.texy @@ -203,4 +203,3 @@ class RecordPresenter extends Nette\Application\UI\Presenter ``` {{priority: -1}} -{{sitename: Best Practices}} diff --git a/best-practices/pt/dynamic-snippets.texy b/best-practices/pt/dynamic-snippets.texy index 7ca7f1e526..a77d207b02 100644 --- a/best-practices/pt/dynamic-snippets.texy +++ b/best-practices/pt/dynamic-snippets.texy @@ -171,4 +171,3 @@ O template da view será reduzido ao mínimo necessário (e completamente livre Estamos quase lá: a aplicação agora funcionará com AJAX. Aqui também teremos que otimizar a aplicação, porque devido ao uso do Nette Database, ao processar o sinal, todos os artigos são carregados desnecessariamente do banco de dados em vez de apenas um. A vantagem, no entanto, é que eles não serão renderizados, pois apenas nosso componente será renderizado. {{priority: -1}} -{{sitename: Best Practices}} diff --git a/best-practices/pt/editors-and-tools.texy b/best-practices/pt/editors-and-tools.texy index 410005d8eb..6d841136f7 100644 --- a/best-practices/pt/editors-and-tools.texy +++ b/best-practices/pt/editors-and-tools.texy @@ -82,5 +82,3 @@ Requirements Checker ==================== Era uma ferramenta que testava o ambiente de execução do servidor e informava se (e em que medida) o framework poderia ser usado. Atualmente, o Nette pode ser usado em qualquer servidor que tenha a versão mínima exigida do PHP. - -{{sitename: Best Practices}} diff --git a/best-practices/pt/form-reuse.texy b/best-practices/pt/form-reuse.texy index ec962c3985..a1c88ae4c5 100644 --- a/best-practices/pt/form-reuse.texy +++ b/best-practices/pt/form-reuse.texy @@ -346,5 +346,3 @@ class MyPresenter extends Nette\Application\UI\Presenter } } ``` - -{{sitename: Best Practices}} diff --git a/best-practices/pt/inject-method-attribute.texy b/best-practices/pt/inject-method-attribute.texy index 97af16f165..c5b05410c2 100644 --- a/best-practices/pt/inject-method-attribute.texy +++ b/best-practices/pt/inject-method-attribute.texy @@ -59,6 +59,3 @@ class MyPresenter extends Nette\Application\UI\Presenter A vantagem dessa forma de passar dependências era a forma de escrita muito concisa. No entanto, com a chegada da [promoção de propriedades do construtor |https://blog.nette.org/pt/php-8-0-complete-overview-of-news#toc-constructor-property-promotion], parece mais fácil usar o construtor. Por outro lado, essa forma sofre das mesmas desvantagens que a passagem de dependências para propriedades em geral: não temos controle sobre as alterações na variável e, ao mesmo tempo, a variável se torna parte da interface pública da classe, o que é indesejável. - - -{{sitename: Best Practices}} diff --git a/best-practices/pt/lets-create-contact-form.texy b/best-practices/pt/lets-create-contact-form.texy index 147d68034f..f75fa749a8 100644 --- a/best-practices/pt/lets-create-contact-form.texy +++ b/best-practices/pt/lets-create-contact-form.texy @@ -219,6 +219,3 @@ parameters: ``` E está pronto! - - -{{sitename: Best Practices}} diff --git a/best-practices/pt/microsites.texy b/best-practices/pt/microsites.texy index c4194f071c..92abd0db15 100644 --- a/best-practices/pt/microsites.texy +++ b/best-practices/pt/microsites.texy @@ -61,5 +61,3 @@ Por que usar Nette para microsites? - Às vezes, pode ser útil usar [cache|caching:], por exemplo, se você baixa e exibe feeds. Nos dias de hoje, onde a velocidade e a eficiência são cruciais, é importante ter ferramentas que permitam alcançar resultados sem atrasos desnecessários. O framework Nette oferece exatamente isso - desenvolvimento rápido, segurança e uma ampla gama de ferramentas, como Tracy e Latte, que simplificam o processo. Basta instalar alguns pacotes Nette e construir tal microsite torna-se de repente uma brincadeira de criança. E você sabe que não há nenhuma falha de segurança escondida em lugar nenhum. - -{{sitename: Best Practices}} diff --git a/best-practices/pt/pagination.texy b/best-practices/pt/pagination.texy index 0af3597abe..a1ec4b1351 100644 --- a/best-practices/pt/pagination.texy +++ b/best-practices/pt/pagination.texy @@ -271,4 +271,3 @@ Como agora não enviamos o Paginator para o template, modificamos a parte que ex Desta forma, implementamos o mecanismo de paginação usando o Nette Database Explorer sem a necessidade explícita do Paginator. {{priority: -1}} -{{sitename: Best Practices}} diff --git a/best-practices/pt/passing-settings-to-presenters.texy b/best-practices/pt/passing-settings-to-presenters.texy index 95355f94f5..a9f8a66798 100644 --- a/best-practices/pt/passing-settings-to-presenters.texy +++ b/best-practices/pt/passing-settings-to-presenters.texy @@ -47,5 +47,3 @@ class MyPresenter extends Nette\Application\UI\Presenter } } ``` - -{{sitename: Best Practices}} diff --git a/best-practices/pt/post-links.texy b/best-practices/pt/post-links.texy index ed748d935e..b1ddb720ee 100644 --- a/best-practices/pt/post-links.texy +++ b/best-practices/pt/post-links.texy @@ -54,6 +54,3 @@ public function handleDelete(int $id): void ``` Esta abordagem não só melhora a segurança da sua aplicação, mas também contribui para a adesão aos padrões e práticas corretas da web. Ao utilizar métodos POST para ações que alteram o estado, você alcançará uma aplicação mais robusta e segura. - - -{{sitename: Best Practices}} diff --git a/best-practices/pt/presenter-traits.texy b/best-practices/pt/presenter-traits.texy index bc0e12749f..0a6ad31278 100644 --- a/best-practices/pt/presenter-traits.texy +++ b/best-practices/pt/presenter-traits.texy @@ -45,6 +45,3 @@ class ArticlePresenter extends Nette\Application\UI\Presenter use RequireLoggedUser; } ``` - - -{{sitename: Best Practices}} diff --git a/best-practices/pt/restore-request.texy b/best-practices/pt/restore-request.texy index 520e15b4e5..c46f2ecb8d 100644 --- a/best-practices/pt/restore-request.texy +++ b/best-practices/pt/restore-request.texy @@ -60,4 +60,3 @@ Passamos a chave da requisição salva para o método `restoreRequest()` e ele r No entanto, se a chave for inválida (por exemplo, não existir mais na sessão), o método não faz nada. Segue-se então a chamada `$this->redirect('Admin:')`, que redireciona para `AdminPresenter`. {{priority: -1}} -{{sitename: Best Practices}} diff --git a/best-practices/ro/@home.texy b/best-practices/ro/@home.texy index 580325e2c3..a742e5d015 100644 --- a/best-practices/ro/@home.texy +++ b/best-practices/ro/@home.texy @@ -67,6 +67,3 @@ Sute de înregistrări de la Ultimele Sâmbete și videoclipuri despre Nette pot - -{{sitename: Best Practices}} -{{leftbar: www:@menu-common}} diff --git a/best-practices/ro/@meta.texy b/best-practices/ro/@meta.texy new file mode 100644 index 0000000000..738844dc28 --- /dev/null +++ b/best-practices/ro/@meta.texy @@ -0,0 +1,2 @@ +{{sitename: Tutoriale și proceduri}} +{{leftbar: www:@menu-common}} diff --git a/best-practices/ro/attribute-requires.texy b/best-practices/ro/attribute-requires.texy index ce24c65df6..26bc6f5e2b 100644 --- a/best-practices/ro/attribute-requires.texy +++ b/best-practices/ro/attribute-requires.texy @@ -175,5 +175,3 @@ Concluzie --------- Atributul `#[Requires]` vă oferă o mare flexibilitate și control asupra modului în care paginile dvs. web sunt accesibile. Folosind reguli simple, dar puternice, puteți crește securitatea și funcționarea corectă a aplicației dvs. După cum vedeți, utilizarea atributelor în Nette vă poate nu numai ușura munca, ci și securiza. - -{{sitename: Best Practices}} diff --git a/best-practices/ro/composer.texy b/best-practices/ro/composer.texy index 631d9e2a54..2e63994768 100644 --- a/best-practices/ro/composer.texy +++ b/best-practices/ro/composer.texy @@ -280,5 +280,3 @@ Composer este strâns legat de instrumentul de versionare [Git |https://git-scm. ```shell composer -g config preferred-install dist ``` - -{{sitename: Best Practices}} diff --git a/best-practices/ro/creating-editing-form.texy b/best-practices/ro/creating-editing-form.texy index af2a3d0887..8c58fc221a 100644 --- a/best-practices/ro/creating-editing-form.texy +++ b/best-practices/ro/creating-editing-form.texy @@ -203,4 +203,3 @@ class RecordPresenter extends Nette\Application\UI\Presenter ``` {{priority: -1}} -{{sitename: Best Practices}} diff --git a/best-practices/ro/dynamic-snippets.texy b/best-practices/ro/dynamic-snippets.texy index 02d427c11f..f6879f7488 100644 --- a/best-practices/ro/dynamic-snippets.texy +++ b/best-practices/ro/dynamic-snippets.texy @@ -171,4 +171,3 @@ protected function createComponentLikeControl() Aproape am terminat: aplicația va funcționa acum cu AJAX. Și aici va trebui să optimizăm aplicația, deoarece, datorită utilizării Nette Database, la procesarea semnalului se încarcă inutil toate articolele din baza de date în loc de unul singur. Avantajul este însă că acestea nu vor fi redate, deoarece se va reda efectiv doar componenta noastră. {{priority: -1}} -{{sitename: Best Practices}} diff --git a/best-practices/ro/editors-and-tools.texy b/best-practices/ro/editors-and-tools.texy index 602f1411ce..7c44d258a6 100644 --- a/best-practices/ro/editors-and-tools.texy +++ b/best-practices/ro/editors-and-tools.texy @@ -82,5 +82,3 @@ Requirements Checker ==================== Acesta a fost un instrument care testa mediul de rulare al serverului și informa dacă (și în ce măsură) framework-ul poate fi utilizat. În prezent, Nette poate fi utilizat pe orice server care are versiunea minimă necesară de PHP. - -{{sitename: Best Practices}} diff --git a/best-practices/ro/form-reuse.texy b/best-practices/ro/form-reuse.texy index a34327c36a..20b7c45804 100644 --- a/best-practices/ro/form-reuse.texy +++ b/best-practices/ro/form-reuse.texy @@ -346,5 +346,3 @@ class MyPresenter extends Nette\Application\UI\Presenter } } ``` - -{{sitename: Best Practices}} diff --git a/best-practices/ro/inject-method-attribute.texy b/best-practices/ro/inject-method-attribute.texy index 6520005009..0479b38c22 100644 --- a/best-practices/ro/inject-method-attribute.texy +++ b/best-practices/ro/inject-method-attribute.texy @@ -59,6 +59,3 @@ class MyPresenter extends Nette\Application\UI\Presenter Avantajul acestei metode de transmitere a dependențelor a fost forma foarte concisă a scrierii. Cu toate acestea, odată cu apariția [constructor property promotion |https://blog.nette.org/ro/php-8-0-complete-overview-of-news#toc-constructor-property-promotion], pare mai ușor să folosești constructorul. Pe de altă parte, această metodă suferă de aceleași neajunsuri ca și transmiterea dependențelor către proprietăți în general: nu avem control asupra modificărilor din variabilă și, în același timp, variabila devine parte a interfeței publice a clasei, ceea ce este nedorit. - - -{{sitename: Best Practices}} diff --git a/best-practices/ro/lets-create-contact-form.texy b/best-practices/ro/lets-create-contact-form.texy index db79dd3f3c..9ae4c05523 100644 --- a/best-practices/ro/lets-create-contact-form.texy +++ b/best-practices/ro/lets-create-contact-form.texy @@ -219,6 +219,3 @@ parameters: ``` Și am terminat! - - -{{sitename: Best Practices}} diff --git a/best-practices/ro/microsites.texy b/best-practices/ro/microsites.texy index 8170575e64..6c4441df8b 100644 --- a/best-practices/ro/microsites.texy +++ b/best-practices/ro/microsites.texy @@ -61,5 +61,3 @@ De ce să folosiți Nette pentru microsite-uri? - Uneori vă poate fi utilă [cache-uirea |caching:], de exemplu dacă descărcați și afișați feed-uri. În zilele noastre, când viteza și eficiența sunt esențiale, este important să aveți instrumente care vă permit să obțineți rezultate fără întârzieri inutile. Nette framework vă oferă exact asta - dezvoltare rapidă, securitate și o gamă largă de instrumente, cum ar fi Tracy și Latte, care simplifică procesul. Este suficient să instalați câteva pachete Nette și construirea unui astfel de microsite devine brusc o joacă de copii. Și știți că nu se ascunde nicio gaură de securitate nicăieri. - -{{sitename: Best Practices}} diff --git a/best-practices/ro/pagination.texy b/best-practices/ro/pagination.texy index 8568297eb3..fe8b8e2114 100644 --- a/best-practices/ro/pagination.texy +++ b/best-practices/ro/pagination.texy @@ -271,4 +271,3 @@ Deoarece acum nu trimitem `Paginator` către șablon, modificăm partea care afi În acest mod am implementat mecanismul de paginare fără utilizarea Paginatorului. {{priority: -1}} -{{sitename: Best Practices}} diff --git a/best-practices/ro/passing-settings-to-presenters.texy b/best-practices/ro/passing-settings-to-presenters.texy index dfc853fa13..0b0e2883ee 100644 --- a/best-practices/ro/passing-settings-to-presenters.texy +++ b/best-practices/ro/passing-settings-to-presenters.texy @@ -47,5 +47,3 @@ class MyPresenter extends Nette\Application\UI\Presenter } } ``` - -{{sitename: Best Practices}} diff --git a/best-practices/ro/post-links.texy b/best-practices/ro/post-links.texy index 27676fcd2d..449a9de1c5 100644 --- a/best-practices/ro/post-links.texy +++ b/best-practices/ro/post-links.texy @@ -54,6 +54,3 @@ public function handleDelete(int $id): void ``` Această abordare nu numai că îmbunătățește securitatea aplicației dvs., dar contribuie și la respectarea standardelor și practicilor web corecte. Prin utilizarea metodelor POST pentru acțiunile care modifică starea, veți obține o aplicație mai robustă și mai sigură. - - -{{sitename: Best Practices}} diff --git a/best-practices/ro/presenter-traits.texy b/best-practices/ro/presenter-traits.texy index db57366033..a074c21292 100644 --- a/best-practices/ro/presenter-traits.texy +++ b/best-practices/ro/presenter-traits.texy @@ -45,6 +45,3 @@ class ArticlePresenter extends Nette\Application\UI\Presenter use RequireLoggedUser; } ``` - - -{{sitename: Best Practices}} diff --git a/best-practices/ro/restore-request.texy b/best-practices/ro/restore-request.texy index 3071c05c24..a8cee5857c 100644 --- a/best-practices/ro/restore-request.texy +++ b/best-practices/ro/restore-request.texy @@ -60,4 +60,3 @@ Metodei `restoreRequest()` îi transmitem cheia cererii salvate și aceasta redi Dacă însă cheia este invalidă (de exemplu, nu mai există în sesiune), metoda nu face nimic. Urmează deci apelul `$this->redirect('Admin:')`, care redirecționează către `AdminPresenter`. {{priority: -1}} -{{sitename: Best Practices}} diff --git a/best-practices/ru/@home.texy b/best-practices/ru/@home.texy index 2f6fc4121c..1ea3ce7e1e 100644 --- a/best-practices/ru/@home.texy +++ b/best-practices/ru/@home.texy @@ -67,6 +67,3 @@ - -{{sitename: Лучшие практики}} -{{leftbar: www:@menu-common}} diff --git a/best-practices/ru/@meta.texy b/best-practices/ru/@meta.texy new file mode 100644 index 0000000000..6463960eed --- /dev/null +++ b/best-practices/ru/@meta.texy @@ -0,0 +1,2 @@ +{{sitename: Руководства и лучшие практики}} +{{leftbar: www:@menu-common}} diff --git a/best-practices/ru/attribute-requires.texy b/best-practices/ru/attribute-requires.texy index 99854f0bfe..8fafce3e80 100644 --- a/best-practices/ru/attribute-requires.texy +++ b/best-practices/ru/attribute-requires.texy @@ -175,5 +175,3 @@ class ApiPresenter extends Nette\Application\UI\Presenter ---------- Атрибут `#[Requires]` дает вам большую гибкость и контроль над тем, как доступны ваши веб-страницы. С помощью простых, но мощных правил вы можете повысить безопасность и правильное функционирование вашего приложения. Как видите, использование атрибутов в Nette может не только упростить вашу работу, но и обезопасить ее. - -{{sitename: Best Practices}} diff --git a/best-practices/ru/composer.texy b/best-practices/ru/composer.texy index bc2c64c211..b8f63ccad6 100644 --- a/best-practices/ru/composer.texy +++ b/best-practices/ru/composer.texy @@ -280,5 +280,3 @@ Composer тесно связан с инструментом версионир ```shell composer -g config preferred-install dist ``` - -{{sitename: Best Practices}} diff --git a/best-practices/ru/creating-editing-form.texy b/best-practices/ru/creating-editing-form.texy index 259d1c436c..bc6b5b84e1 100644 --- a/best-practices/ru/creating-editing-form.texy +++ b/best-practices/ru/creating-editing-form.texy @@ -203,4 +203,3 @@ class RecordPresenter extends Nette\Application\UI\Presenter ``` {{priority: -1}} -{{sitename: Best Practices}} diff --git a/best-practices/ru/dynamic-snippets.texy b/best-practices/ru/dynamic-snippets.texy index 20badb7eee..30a58602e3 100644 --- a/best-practices/ru/dynamic-snippets.texy +++ b/best-practices/ru/dynamic-snippets.texy @@ -171,4 +171,3 @@ protected function createComponentLikeControl() Почти готово: приложение теперь будет работать с AJAX. Здесь нас также ждет оптимизация приложения, потому что из-за использования Nette Database при обработке сигнала из базы данных излишне загружаются все статьи вместо одной. Преимуществом, однако, является то, что их отрисовка не происходит, потому что рендерится действительно только наш компонент. {{priority: -1}} -{{sitename: Best Practices}} diff --git a/best-practices/ru/editors-and-tools.texy b/best-practices/ru/editors-and-tools.texy index 97a6642ccb..7508f40017 100644 --- a/best-practices/ru/editors-and-tools.texy +++ b/best-practices/ru/editors-and-tools.texy @@ -82,5 +82,3 @@ Requirements Checker ==================== Это был инструмент, который тестировал среду выполнения сервера и сообщал, можно ли (и в какой степени) использовать фреймворк. В настоящее время Nette можно использовать на любом сервере, имеющем минимально требуемую версию PHP. - -{{sitename: Best Practices}} diff --git a/best-practices/ru/form-reuse.texy b/best-practices/ru/form-reuse.texy index 89ed9eda31..2c8dd3114c 100644 --- a/best-practices/ru/form-reuse.texy +++ b/best-practices/ru/form-reuse.texy @@ -346,5 +346,3 @@ class MyPresenter extends Nette\Application\UI\Presenter } } ``` - -{{sitename: Best Practices}} diff --git a/best-practices/ru/inject-method-attribute.texy b/best-practices/ru/inject-method-attribute.texy index d8da611af2..689ddbfa3c 100644 --- a/best-practices/ru/inject-method-attribute.texy +++ b/best-practices/ru/inject-method-attribute.texy @@ -59,6 +59,3 @@ class MyPresenter extends Nette\Application\UI\Presenter Преимуществом этого способа передачи зависимостей была очень лаконичная форма записи. Однако с появлением [constructor property promotion |https://blog.nette.org/ru/php-8-0-complete-overview-of-news#toc-constructor-property-promotion] кажется проще использовать конструктор. Напротив, этот способ страдает теми же недостатками, что и передача зависимости в свойства в целом: у нас нет контроля над изменениями в переменной, и в то же время переменная становится частью публичного интерфейса класса, что нежелательно. - - -{{sitename: Best Practices}} diff --git a/best-practices/ru/lets-create-contact-form.texy b/best-practices/ru/lets-create-contact-form.texy index c8906b0fb1..981a38df9b 100644 --- a/best-practices/ru/lets-create-contact-form.texy +++ b/best-practices/ru/lets-create-contact-form.texy @@ -219,6 +219,3 @@ parameters: ``` И готово! - - -{{sitename: Best Practices}} diff --git a/best-practices/ru/microsites.texy b/best-practices/ru/microsites.texy index f1519cf032..c82e82b71a 100644 --- a/best-practices/ru/microsites.texy +++ b/best-practices/ru/microsites.texy @@ -61,5 +61,3 @@ PHP-код в `index.php` сначала [подготавливает сред - Иногда вам может пригодиться [кеширование|caching:], например, если вы скачиваете и отображаете фиды. В наше время, когда скорость и эффективность являются ключевыми, важно иметь инструменты, которые позволят вам достигать результатов без лишних задержек. Фреймворк Nette предлагает именно это - быструю разработку, безопасность и широкий спектр инструментов, таких как Tracy и Latte, которые упрощают процесс. Достаточно установить несколько пакетов Nette, и создание такого микросайта становится совершенно простым делом. И вы знаете, что нигде не скрывается никакой дыры в безопасности. - -{{sitename: Best Practices}} diff --git a/best-practices/ru/pagination.texy b/best-practices/ru/pagination.texy index 99d59c4272..15756e6d22 100644 --- a/best-practices/ru/pagination.texy +++ b/best-practices/ru/pagination.texy @@ -271,4 +271,3 @@ class HomePresenter extends Nette\Application\UI\Presenter Таким образом, мы реализовали механизм пагинации без использования Paginator. {{priority: -1}} -{{sitename: Best Practices}} diff --git a/best-practices/ru/passing-settings-to-presenters.texy b/best-practices/ru/passing-settings-to-presenters.texy index c4d0f44be3..b65b1186c6 100644 --- a/best-practices/ru/passing-settings-to-presenters.texy +++ b/best-practices/ru/passing-settings-to-presenters.texy @@ -47,5 +47,3 @@ class MyPresenter extends Nette\Application\UI\Presenter } } ``` - -{{sitename: Best Practices}} diff --git a/best-practices/ru/post-links.texy b/best-practices/ru/post-links.texy index 1783d13aed..59daf4a9e5 100644 --- a/best-practices/ru/post-links.texy +++ b/best-practices/ru/post-links.texy @@ -54,6 +54,3 @@ public function handleDelete(int $id): void ``` Этот подход не только улучшает безопасность вашего приложения, но и способствует соблюдению правильных веб-стандартов и практик. Используя методы POST для действий, изменяющих состояние, вы достигнете более надежного и безопасного приложения. - - -{{sitename: Best Practices}} diff --git a/best-practices/ru/presenter-traits.texy b/best-practices/ru/presenter-traits.texy index 00d90c6d73..96d90aef15 100644 --- a/best-practices/ru/presenter-traits.texy +++ b/best-practices/ru/presenter-traits.texy @@ -45,6 +45,3 @@ class ArticlePresenter extends Nette\Application\UI\Presenter use RequireLoggedUser; } ``` - - -{{sitename: Best Practices}} diff --git a/best-practices/ru/restore-request.texy b/best-practices/ru/restore-request.texy index ce9771090b..19f5c12df1 100644 --- a/best-practices/ru/restore-request.texy +++ b/best-practices/ru/restore-request.texy @@ -60,4 +60,3 @@ class SignPresenter extends Nette\Application\UI\Presenter Однако, если ключ недействителен (например, его уже нет в сессии), метод ничего не делает. Затем следует вызов `$this->redirect('Admin:')`, который перенаправляет на `AdminPresenter`. {{priority: -1}} -{{sitename: Best Practices}} diff --git a/best-practices/sl/@home.texy b/best-practices/sl/@home.texy index 76a34361e5..a4cf0efbec 100644 --- a/best-practices/sl/@home.texy +++ b/best-practices/sl/@home.texy @@ -67,6 +67,3 @@ Stotine posnetkov iz Poslednjih sobot in videov o Nette najdete pod eno streho n - -{{sitename: Best Practices}} -{{leftbar: www:@menu-common}} diff --git a/best-practices/sl/@meta.texy b/best-practices/sl/@meta.texy new file mode 100644 index 0000000000..f58ad17850 --- /dev/null +++ b/best-practices/sl/@meta.texy @@ -0,0 +1,2 @@ +{{sitename: Navodila in postopki}} +{{leftbar: www:@menu-common}} diff --git a/best-practices/sl/attribute-requires.texy b/best-practices/sl/attribute-requires.texy index 1f3334ed4b..8fb0588c40 100644 --- a/best-practices/sl/attribute-requires.texy +++ b/best-practices/sl/attribute-requires.texy @@ -175,5 +175,3 @@ Zaključek --------- Atribut `#[Requires]` vam daje veliko fleksibilnosti in nadzora nad tem, kako so vaše spletne strani dostopne. S pomočjo preprostih, a močnih pravil lahko povečate varnost in pravilno delovanje vaše aplikacije. Kot vidite, lahko uporaba atributov v Nette vaše delo ne samo olajša, ampak tudi zavaruje. - -{{sitename: Best Practices}} diff --git a/best-practices/sl/composer.texy b/best-practices/sl/composer.texy index 177d01f103..bcfe1802c9 100644 --- a/best-practices/sl/composer.texy +++ b/best-practices/sl/composer.texy @@ -280,5 +280,3 @@ Composer je tesno povezan z orodjem za verzioniranje [Git |https://git-scm.com]. ```shell composer -g config preferred-install dist ``` - -{{sitename: Best Practices}} diff --git a/best-practices/sl/creating-editing-form.texy b/best-practices/sl/creating-editing-form.texy index 6d3837b4d3..650812cb3a 100644 --- a/best-practices/sl/creating-editing-form.texy +++ b/best-practices/sl/creating-editing-form.texy @@ -203,4 +203,3 @@ class RecordPresenter extends Nette\Application\UI\Presenter ``` {{priority: -1}} -{{sitename: Best Practices}} diff --git a/best-practices/sl/dynamic-snippets.texy b/best-practices/sl/dynamic-snippets.texy index c6e6258a1d..1f5704cd9c 100644 --- a/best-practices/sl/dynamic-snippets.texy +++ b/best-practices/sl/dynamic-snippets.texy @@ -171,4 +171,3 @@ Predloga pogleda (view) se zmanjša na nujni minimum (in je popolnoma brez snipp Skoraj smo končali: aplikacija bo zdaj delovala AJAX-ovsko. Tudi tukaj nas čaka optimizacija aplikacije, saj se zaradi uporabe Nette Database pri obdelavi signala nepotrebno naložijo vsi članki iz podatkovne baze namesto enega. Prednost pa je, da ne pride do njihovega izrisovanja, ker se dejansko izriše samo naša komponenta. {{priority: -1}} -{{sitename: Best Practices}} diff --git a/best-practices/sl/editors-and-tools.texy b/best-practices/sl/editors-and-tools.texy index e9473cb593..9ac5d2ff3c 100644 --- a/best-practices/sl/editors-and-tools.texy +++ b/best-practices/sl/editors-and-tools.texy @@ -82,5 +82,3 @@ Requirements Checker ==================== To je bilo orodje, ki je testiralo izvajalno okolje strežnika in obveščalo, ali (in v kolikšni meri) je mogoče ogrodje uporabljati. Trenutno je Nette mogoče uporabljati na vsakem strežniku, ki ima minimalno zahtevano različico PHP. - -{{sitename: Best Practices}} diff --git a/best-practices/sl/form-reuse.texy b/best-practices/sl/form-reuse.texy index fb33c64c4f..4a388acd07 100644 --- a/best-practices/sl/form-reuse.texy +++ b/best-practices/sl/form-reuse.texy @@ -346,5 +346,3 @@ class MyPresenter extends Nette\Application\UI\Presenter } } ``` - -{{sitename: Best Practices}} diff --git a/best-practices/sl/inject-method-attribute.texy b/best-practices/sl/inject-method-attribute.texy index 6b501ca408..e09c5e2471 100644 --- a/best-practices/sl/inject-method-attribute.texy +++ b/best-practices/sl/inject-method-attribute.texy @@ -59,6 +59,3 @@ class MyPresenter extends Nette\Application\UI\Presenter Prednost tega načina posredovanja odvisnosti je bila zelo varčna oblika zapisa. Vendar pa se z uvedbo [constructor property promotion |https://blog.nette.org/sl/php-8-0-complete-overview-of-news#toc-constructor-property-promotion] zdi lažje uporabiti konstruktor. Nasprotno pa ta način trpi za enakimi pomanjkljivostmi kot posredovanje odvisnosti v lastnosti (properties) na splošno: nimamo nadzora nad spremembami v spremenljivki in hkrati spremenljivka postane del javnega vmesnika razreda, kar je nezaželeno. - - -{{sitename: Best Practices}} diff --git a/best-practices/sl/lets-create-contact-form.texy b/best-practices/sl/lets-create-contact-form.texy index 9f5c5874e6..ed3d4baf0b 100644 --- a/best-practices/sl/lets-create-contact-form.texy +++ b/best-practices/sl/lets-create-contact-form.texy @@ -219,6 +219,3 @@ parameters: ``` In končano! - - -{{sitename: Best Practices}} diff --git a/best-practices/sl/microsites.texy b/best-practices/sl/microsites.texy index c73853d1d2..fd4a5be3f2 100644 --- a/best-practices/sl/microsites.texy +++ b/best-practices/sl/microsites.texy @@ -61,5 +61,3 @@ Zakaj uporabljati Nette za mikro-spletna mesta? - Včasih vam lahko koristi [predpomnjenje|caching:], na primer če prenašate in prikazujete vire (feeds). V današnjem času, ko sta hitrost in učinkovitost ključnega pomena, je pomembno imeti orodja, ki vam omogočajo doseganje rezultatov brez nepotrebnega odlašanja. Ogrodje Nette vam ponuja prav to - hiter razvoj, varnost in široko paleto orodij, kot sta Tracy in Latte, ki poenostavljajo proces. Dovolj je namestiti nekaj Nette paketov in zgraditi takšno mikro-spletno mesto je naenkrat povsem enostavno. In veste, da se nikjer ne skriva nobena varnostna luknja. - -{{sitename: Best Practices}} diff --git a/best-practices/sl/pagination.texy b/best-practices/sl/pagination.texy index 8047731a85..f543008252 100644 --- a/best-practices/sl/pagination.texy +++ b/best-practices/sl/pagination.texy @@ -271,4 +271,3 @@ Ker v predlogo zdaj ne pošiljamo Paginatorja, prilagodimo del, ki prikazuje pov Na ta način smo implementirali mehanizem za stranskanje brez uporabe Paginatorja. {{priority: -1}} -{{sitename: Best Practices}} diff --git a/best-practices/sl/passing-settings-to-presenters.texy b/best-practices/sl/passing-settings-to-presenters.texy index 4a4e6a67b4..8ced4b88f2 100644 --- a/best-practices/sl/passing-settings-to-presenters.texy +++ b/best-practices/sl/passing-settings-to-presenters.texy @@ -47,5 +47,3 @@ class MyPresenter extends Nette\Application\UI\Presenter } } ``` - -{{sitename: Best Practices}} diff --git a/best-practices/sl/post-links.texy b/best-practices/sl/post-links.texy index 752b22733a..0b99158d78 100644 --- a/best-practices/sl/post-links.texy +++ b/best-practices/sl/post-links.texy @@ -54,6 +54,3 @@ public function handleDelete(int $id): void ``` Ta pristop ne samo izboljšuje varnost vaše aplikacije, ampak tudi prispeva k spoštovanju pravilnih spletnih standardov in praks. Z uporabo metod POST za akcije, ki spreminjajo stanje, dosežete bolj robustno in varnejšo aplikacijo. - - -{{sitename: Best Practices}} diff --git a/best-practices/sl/presenter-traits.texy b/best-practices/sl/presenter-traits.texy index b07e18f8de..894c0add0e 100644 --- a/best-practices/sl/presenter-traits.texy +++ b/best-practices/sl/presenter-traits.texy @@ -45,6 +45,3 @@ class ArticlePresenter extends Nette\Application\UI\Presenter use RequireLoggedUser; } ``` - - -{{sitename: Best Practices}} diff --git a/best-practices/sl/restore-request.texy b/best-practices/sl/restore-request.texy index 80bdec2010..6f81a2d371 100644 --- a/best-practices/sl/restore-request.texy +++ b/best-practices/sl/restore-request.texy @@ -60,4 +60,3 @@ Metodi `restoreRequest()` posredujemo ključ shranjene zahteve in ta preusmeri ( Če pa je ključ neveljaven (na primer že ne obstaja v seji), metoda ne naredi ničesar. Sledi torej klic `$this->redirect('Admin:')`, ki preusmeri na `AdminPresenter`. {{priority: -1}} -{{sitename: Best Practices}} diff --git a/best-practices/tr/@home.texy b/best-practices/tr/@home.texy index 6a83e8a3f6..c8b90b9e40 100644 --- a/best-practices/tr/@home.texy +++ b/best-practices/tr/@home.texy @@ -67,6 +67,3 @@ Poslední soboty'den yüzlerce kayıt ve Nette hakkındaki videoları tek bir ç - -{{sitename: En İyi Uygulamalar}} -{{leftbar: www:@menu-common}} diff --git a/best-practices/tr/@meta.texy b/best-practices/tr/@meta.texy new file mode 100644 index 0000000000..7f915d9a01 --- /dev/null +++ b/best-practices/tr/@meta.texy @@ -0,0 +1,2 @@ +{{sitename: Kılavuzlar ve yöntemler}} +{{leftbar: www:@menu-common}} diff --git a/best-practices/tr/attribute-requires.texy b/best-practices/tr/attribute-requires.texy index e73ab1f47f..0fe1f082f5 100644 --- a/best-practices/tr/attribute-requires.texy +++ b/best-practices/tr/attribute-requires.texy @@ -175,5 +175,3 @@ Sonuç ----- `#[Requires]` niteliği, web sayfalarınızın nasıl erişilebilir olduğu konusunda size büyük esneklik ve kontrol sağlar. Basit ama güçlü kurallar kullanarak uygulamanızın güvenliğini ve doğru çalışmasını artırabilirsiniz. Gördüğünüz gibi, Nette'de nitelikleri kullanmak işinizi yalnızca kolaylaştırmakla kalmaz, aynı zamanda güvence altına da alabilir. - -{{sitename: Best Practices}} diff --git a/best-practices/tr/composer.texy b/best-practices/tr/composer.texy index ca8dc89f6d..c0eb5fb788 100644 --- a/best-practices/tr/composer.texy +++ b/best-practices/tr/composer.texy @@ -280,5 +280,3 @@ Composer, [Git |https://git-scm.com] sürüm kontrol aracıyla yakından bağlan ```shell composer -g config preferred-install dist ``` - -{{sitename: Best Practices}} diff --git a/best-practices/tr/creating-editing-form.texy b/best-practices/tr/creating-editing-form.texy index 2bd0873f58..0274a0e122 100644 --- a/best-practices/tr/creating-editing-form.texy +++ b/best-practices/tr/creating-editing-form.texy @@ -203,4 +203,3 @@ class RecordPresenter extends Nette\Application\UI\Presenter ``` {{priority: -1}} -{{sitename: Best Practices}} diff --git a/best-practices/tr/dynamic-snippets.texy b/best-practices/tr/dynamic-snippets.texy index fd04e468c3..c805aeedb5 100644 --- a/best-practices/tr/dynamic-snippets.texy +++ b/best-practices/tr/dynamic-snippets.texy @@ -171,4 +171,3 @@ Görünüm şablonu gerekli minimuma indirildi (ve tamamen snippet'lerden arınd Neredeyse bitti: uygulama artık AJAX ile çalışacak. Burada da uygulamayı optimize etmemiz gerekiyor, çünkü Nette Database kullanımı nedeniyle, sinyal işlenirken veritabanından tüm makaleler gereksiz yere yüklenir, oysa sadece bir tanesi yeterlidir. Ancak avantajı, bunların oluşturulmamasıdır, çünkü gerçekten sadece bizim bileşenimiz oluşturulur. {{priority: -1}} -{{sitename: Best Practices}} diff --git a/best-practices/tr/editors-and-tools.texy b/best-practices/tr/editors-and-tools.texy index d4c17be900..e1822a4311 100644 --- a/best-practices/tr/editors-and-tools.texy +++ b/best-practices/tr/editors-and-tools.texy @@ -82,5 +82,3 @@ Requirements Checker ==================== Sunucunun çalışma zamanı ortamını test eden ve framework'ün kullanılıp kullanılamayacağını (ve ne ölçüde) bildiren bir araçtı. Şu anda Nette, minimum gerekli PHP sürümüne sahip her sunucuda kullanılabilir. - -{{sitename: Best Practices}} diff --git a/best-practices/tr/form-reuse.texy b/best-practices/tr/form-reuse.texy index e9c842e565..224e9f00d7 100644 --- a/best-practices/tr/form-reuse.texy +++ b/best-practices/tr/form-reuse.texy @@ -346,5 +346,3 @@ class MyPresenter extends Nette\Application\UI\Presenter } } ``` - -{{sitename: Best Practices}} diff --git a/best-practices/tr/inject-method-attribute.texy b/best-practices/tr/inject-method-attribute.texy index cdf5ca75bb..95d08e2e06 100644 --- a/best-practices/tr/inject-method-attribute.texy +++ b/best-practices/tr/inject-method-attribute.texy @@ -59,6 +59,3 @@ class MyPresenter extends Nette\Application\UI\Presenter Bu bağımlılık iletme yönteminin avantajı, çok kısa bir yazım şekli olmasıydı. Ancak, [constructor property promotion |https://blog.nette.org/tr/php-8-0-complete-overview-of-news#toc-constructor-property-promotion] 'ın gelişiyle, yapıcıyı kullanmak daha kolay görünüyor. Tersine, bu yöntem, genel olarak özelliklere bağımlılık iletmeyle aynı dezavantajlara sahiptir: değişken üzerindeki değişiklikler üzerinde kontrolümüz yoktur ve aynı zamanda değişken, sınıfın genel arayüzünün bir parçası haline gelir, ki bu istenmeyen bir durumdur. - - -{{sitename: Best Practices}} diff --git a/best-practices/tr/lets-create-contact-form.texy b/best-practices/tr/lets-create-contact-form.texy index b16c31a93f..042f486703 100644 --- a/best-practices/tr/lets-create-contact-form.texy +++ b/best-practices/tr/lets-create-contact-form.texy @@ -219,6 +219,3 @@ parameters: ``` Ve işimiz bitti! - - -{{sitename: Best Practices}} diff --git a/best-practices/tr/microsites.texy b/best-practices/tr/microsites.texy index daaf4087cf..fca2a1ebeb 100644 --- a/best-practices/tr/microsites.texy +++ b/best-practices/tr/microsites.texy @@ -61,5 +61,3 @@ Neden mikro siteler için Nette kullanmalı? - Bazen [önbelleğe alma|caching:] işinize yarayabilir, örneğin beslemeleri indirip görüntülüyorsanız. Hız ve verimliliğin anahtar olduğu günümüzde, gereksiz gecikmeler olmadan sonuçlara ulaşmanızı sağlayan araçlara sahip olmak önemlidir. Nette framework size tam da bunu sunar - hızlı geliştirme, güvenlik ve süreci basitleştiren Tracy ve Latte gibi geniş bir araç yelpazesi. Sadece birkaç Nette paketi yükleyin ve böyle bir mikro site oluşturmak birdenbire çocuk oyuncağı haline gelir. Ve hiçbir yerde gizli bir güvenlik açığı olmadığını bilirsiniz. - -{{sitename: Best Practices}} diff --git a/best-practices/tr/pagination.texy b/best-practices/tr/pagination.texy index 913c5dfe47..92509706a7 100644 --- a/best-practices/tr/pagination.texy +++ b/best-practices/tr/pagination.texy @@ -271,4 +271,3 @@ class HomePresenter extends Nette\Application\UI\Presenter Bu şekilde, Paginator kullanmadan sayfalama mekanizmasını uyguladık. {{priority: -1}} -{{sitename: Best Practices}} diff --git a/best-practices/tr/passing-settings-to-presenters.texy b/best-practices/tr/passing-settings-to-presenters.texy index 454f5157aa..b71ddc741d 100644 --- a/best-practices/tr/passing-settings-to-presenters.texy +++ b/best-practices/tr/passing-settings-to-presenters.texy @@ -47,5 +47,3 @@ class MyPresenter extends Nette\Application\UI\Presenter } } ``` - -{{sitename: Best Practices}} diff --git a/best-practices/tr/post-links.texy b/best-practices/tr/post-links.texy index 7c22376f68..4d4ca45666 100644 --- a/best-practices/tr/post-links.texy +++ b/best-practices/tr/post-links.texy @@ -54,6 +54,3 @@ public function handleDelete(int $id): void ``` Bu yaklaşım yalnızca uygulamanızın güvenliğini artırmakla kalmaz, aynı zamanda doğru web standartlarına ve uygulamalarına uymaya da katkıda bulunur. Durumu değiştiren eylemler için POST yöntemlerini kullanarak daha sağlam ve güvenli bir uygulama elde edersiniz. - - -{{sitename: Best Practices}} diff --git a/best-practices/tr/presenter-traits.texy b/best-practices/tr/presenter-traits.texy index 40751aea03..a75c15f500 100644 --- a/best-practices/tr/presenter-traits.texy +++ b/best-practices/tr/presenter-traits.texy @@ -45,6 +45,3 @@ class ArticlePresenter extends Nette\Application\UI\Presenter use RequireLoggedUser; } ``` - - -{{sitename: Best Practices}} diff --git a/best-practices/tr/restore-request.texy b/best-practices/tr/restore-request.texy index 3ad6156f6b..0316b1cc68 100644 --- a/best-practices/tr/restore-request.texy +++ b/best-practices/tr/restore-request.texy @@ -60,4 +60,3 @@ class SignPresenter extends Nette\Application\UI\Presenter Ancak anahtar geçersizse (örneğin, artık oturumda mevcut değilse), metot hiçbir şey yapmaz. Bu nedenle, `AdminPresenter`'a yönlendiren `$this->redirect('Admin:')` çağrısı takip eder. {{priority: -1}} -{{sitename: Best Practices}} diff --git a/best-practices/uk/@home.texy b/best-practices/uk/@home.texy index 7ea5601bb5..f9d3510c2b 100644 --- a/best-practices/uk/@home.texy +++ b/best-practices/uk/@home.texy @@ -67,6 +67,3 @@ - -{{sitename: Найкращі практики}} -{{leftbar: www:@menu-common}} diff --git a/best-practices/uk/@meta.texy b/best-practices/uk/@meta.texy new file mode 100644 index 0000000000..5ad8bb9a6b --- /dev/null +++ b/best-practices/uk/@meta.texy @@ -0,0 +1,2 @@ +{{sitename: Посібники та практики}} +{{leftbar: www:@menu-common}} diff --git a/best-practices/uk/attribute-requires.texy b/best-practices/uk/attribute-requires.texy index ed222211dd..f0d8d4a2d1 100644 --- a/best-practices/uk/attribute-requires.texy +++ b/best-practices/uk/attribute-requires.texy @@ -175,5 +175,3 @@ class ApiPresenter extends Nette\Application\UI\Presenter -------- Атрибут `#[Requires]` надає вам велику гнучкість і контроль над тим, як доступні ваші веб-сторінки. За допомогою простих, але потужних правил ви можете підвищити безпеку та правильне функціонування вашого додатку. Як бачите, використання атрибутів у Nette може не тільки полегшити вашу роботу, але й зробити її безпечнішою. - -{{sitename: Best Practices}} diff --git a/best-practices/uk/composer.texy b/best-practices/uk/composer.texy index b49e376877..a237caf401 100644 --- a/best-practices/uk/composer.texy +++ b/best-practices/uk/composer.texy @@ -280,5 +280,3 @@ Composer тісно пов'язаний з інструментом версіо ```shell composer -g config preferred-install dist ``` - -{{sitename: Best Practices}} diff --git a/best-practices/uk/creating-editing-form.texy b/best-practices/uk/creating-editing-form.texy index 813666b04c..415142d3ae 100644 --- a/best-practices/uk/creating-editing-form.texy +++ b/best-practices/uk/creating-editing-form.texy @@ -203,4 +203,3 @@ class RecordPresenter extends Nette\Application\UI\Presenter ``` {{priority: -1}} -{{sitename: Best Practices}} diff --git a/best-practices/uk/dynamic-snippets.texy b/best-practices/uk/dynamic-snippets.texy index 790cfe06a9..3a8f9f5f63 100644 --- a/best-practices/uk/dynamic-snippets.texy +++ b/best-practices/uk/dynamic-snippets.texy @@ -171,4 +171,3 @@ protected function createComponentLikeControl() Майже готово: додаток тепер працюватиме за допомогою AJAX. Тут також нас чекає оптимізація додатку, оскільки через використання Nette Database при обробці сигналу марно завантажуються всі статті з бази даних замість однієї. Перевагою, однак, є те, що їх рендеринг не відбудеться, оскільки відрендериться дійсно лише наш компонент. {{priority: -1}} -{{sitename: Best Practices}} diff --git a/best-practices/uk/editors-and-tools.texy b/best-practices/uk/editors-and-tools.texy index 87fc1d8218..86380ff279 100644 --- a/best-practices/uk/editors-and-tools.texy +++ b/best-practices/uk/editors-and-tools.texy @@ -82,5 +82,3 @@ Requirements Checker ==================== Це був інструмент, який тестував середовище виконання сервера та інформував, чи (і якою мірою) можна використовувати фреймворк. На даний момент Nette можна використовувати на будь-якому сервері, який має мінімально необхідну версію PHP. - -{{sitename: Best Practices}} diff --git a/best-practices/uk/form-reuse.texy b/best-practices/uk/form-reuse.texy index b007c85afa..d75d20642b 100644 --- a/best-practices/uk/form-reuse.texy +++ b/best-practices/uk/form-reuse.texy @@ -346,5 +346,3 @@ class MyPresenter extends Nette\Application\UI\Presenter } } ``` - -{{sitename: Best Practices}} diff --git a/best-practices/uk/inject-method-attribute.texy b/best-practices/uk/inject-method-attribute.texy index 5496ce823f..8e64ef27ab 100644 --- a/best-practices/uk/inject-method-attribute.texy +++ b/best-practices/uk/inject-method-attribute.texy @@ -59,6 +59,3 @@ class MyPresenter extends Nette\Application\UI\Presenter Перевагою цього способу передачі залежностей була дуже лаконічна форма запису. Однак з появою [constructor property promotion |https://blog.nette.org/uk/php-8-0-complete-overview-of-news#toc-constructor-property-promotion] простіше використовувати конструктор. Навпаки, цей спосіб страждає тими ж недоліками, що й передача залежності у властивості загалом: ми не маємо контролю над змінами в змінній, і водночас змінна стає частиною публічного інтерфейсу класу, що є небажаним. - - -{{sitename: Best Practices}} diff --git a/best-practices/uk/lets-create-contact-form.texy b/best-practices/uk/lets-create-contact-form.texy index 7cdc5bf2ff..dda0437ab6 100644 --- a/best-practices/uk/lets-create-contact-form.texy +++ b/best-practices/uk/lets-create-contact-form.texy @@ -219,6 +219,3 @@ parameters: ``` І готово! - - -{{sitename: Best Practices}} diff --git a/best-practices/uk/microsites.texy b/best-practices/uk/microsites.texy index 40c404ed7d..19744c4b86 100644 --- a/best-practices/uk/microsites.texy +++ b/best-practices/uk/microsites.texy @@ -61,5 +61,3 @@ PHP-код в `index.php` спочатку [підготує середовищ - Іноді вам може знадобитися [кешування|caching:], наприклад, якщо ви завантажуєте та відображаєте стрічки новин. У наш час, коли швидкість та ефективність є ключовими, важливо мати інструменти, які дозволять вам досягти результатів без зайвих затримок. Фреймворк Nette пропонує саме це - швидку розробку, безпеку та широкий спектр інструментів, таких як Tracy та Latte, які спрощують процес. Достатньо встановити кілька пакетів Nette, і створення такого мікросайту раптом стає зовсім простою справою. І ви знаєте, що ніде не ховається жодна дірка в безпеці. - -{{sitename: Best Practices}} diff --git a/best-practices/uk/pagination.texy b/best-practices/uk/pagination.texy index e34ae7f166..e16f7e4ad4 100644 --- a/best-practices/uk/pagination.texy +++ b/best-practices/uk/pagination.texy @@ -271,4 +271,3 @@ class HomePresenter extends Nette\Application\UI\Presenter Таким чином ми реалізували механізм пагінації без використання Paginator. {{priority: -1}} -{{sitename: Best Practices}} diff --git a/best-practices/uk/passing-settings-to-presenters.texy b/best-practices/uk/passing-settings-to-presenters.texy index 4f3488c8cb..eab473dbda 100644 --- a/best-practices/uk/passing-settings-to-presenters.texy +++ b/best-practices/uk/passing-settings-to-presenters.texy @@ -47,5 +47,3 @@ class MyPresenter extends Nette\Application\UI\Presenter } } ``` - -{{sitename: Best Practices}} diff --git a/best-practices/uk/post-links.texy b/best-practices/uk/post-links.texy index 63e68b4a8c..d0c67a0506 100644 --- a/best-practices/uk/post-links.texy +++ b/best-practices/uk/post-links.texy @@ -54,6 +54,3 @@ public function handleDelete(int $id): void ``` Цей підхід не тільки покращує безпеку вашого додатку, але й сприяє дотриманню правильних веб-стандартів та практик. Використовуючи методи POST для дій, що змінюють стан, ви досягнете більш надійного та безпечного додатку. - - -{{sitename: Best Practices}} diff --git a/best-practices/uk/presenter-traits.texy b/best-practices/uk/presenter-traits.texy index c83bcb32f6..3b4ce8a1cb 100644 --- a/best-practices/uk/presenter-traits.texy +++ b/best-practices/uk/presenter-traits.texy @@ -45,6 +45,3 @@ class ArticlePresenter extends Nette\Application\UI\Presenter use RequireLoggedUser; } ``` - - -{{sitename: Best Practices}} diff --git a/best-practices/uk/restore-request.texy b/best-practices/uk/restore-request.texy index 4bef72edcf..63446e2b95 100644 --- a/best-practices/uk/restore-request.texy +++ b/best-practices/uk/restore-request.texy @@ -60,4 +60,3 @@ class SignPresenter extends Nette\Application\UI\Presenter Однак, якщо ключ недійсний (наприклад, вже не існує в сесії), метод нічого не робить. Тому далі йде виклик `$this->redirect('Admin:')`, який перенаправляє на `AdminPresenter`. {{priority: -1}} -{{sitename: Best Practices}} diff --git a/bootstrap/bg/@home.texy b/bootstrap/bg/@home.texy index 7949a81530..3f9b20f4a1 100644 --- a/bootstrap/bg/@home.texy +++ b/bootstrap/bg/@home.texy @@ -94,6 +94,3 @@ $configurator->addDynamicParameters([ ``` Параметърът `projectId` може да бъде рефериран в конфигурацията чрез запис `%projectId%`. - - -{{leftbar: nette:@menu-topics}} diff --git a/bootstrap/bg/@meta.texy b/bootstrap/bg/@meta.texy new file mode 100644 index 0000000000..794cbc8522 --- /dev/null +++ b/bootstrap/bg/@meta.texy @@ -0,0 +1,2 @@ +{{sitename: Документация на Nette}} +{{leftbar: nette:@menu-topics}} diff --git a/bootstrap/cs/@home.texy b/bootstrap/cs/@home.texy index d1f5e0bdb2..9e3f2acaa6 100644 --- a/bootstrap/cs/@home.texy +++ b/bootstrap/cs/@home.texy @@ -94,6 +94,3 @@ $configurator->addDynamicParameters([ ``` Na parametr `projectId` se lze v konfiguraci odkázat zápisem `%projectId%`. - - -{{leftbar: nette:@menu-topics}} diff --git a/bootstrap/cs/@meta.texy b/bootstrap/cs/@meta.texy new file mode 100644 index 0000000000..08edde785b --- /dev/null +++ b/bootstrap/cs/@meta.texy @@ -0,0 +1,2 @@ +{{sitename: Nette Dokumentace}} +{{leftbar: nette:@menu-topics}} diff --git a/bootstrap/de/@home.texy b/bootstrap/de/@home.texy index 316e9f7db6..8f49650c62 100644 --- a/bootstrap/de/@home.texy +++ b/bootstrap/de/@home.texy @@ -94,6 +94,3 @@ $configurator->addDynamicParameters([ ``` Auf den Parameter `projectId` kann in der Konfiguration mit der Notation `%projectId%` verwiesen werden. - - -{{leftbar: nette:@menu-topics}} diff --git a/bootstrap/de/@meta.texy b/bootstrap/de/@meta.texy new file mode 100644 index 0000000000..2cf383a5cf --- /dev/null +++ b/bootstrap/de/@meta.texy @@ -0,0 +1,2 @@ +{{sitename: Nette Dokumentation}} +{{leftbar: nette:@menu-topics}} diff --git a/bootstrap/el/@home.texy b/bootstrap/el/@home.texy index 01358f0f79..8b4cf46446 100644 --- a/bootstrap/el/@home.texy +++ b/bootstrap/el/@home.texy @@ -94,6 +94,3 @@ $configurator->addDynamicParameters([ ``` Στην παράμετρο `projectId` μπορεί να γίνει αναφορά στη διαμόρφωση με τη σύνταξη `%projectId%`. - - -{{leftbar: nette:@menu-topics}} diff --git a/bootstrap/el/@meta.texy b/bootstrap/el/@meta.texy new file mode 100644 index 0000000000..a09ce5fe0d --- /dev/null +++ b/bootstrap/el/@meta.texy @@ -0,0 +1,2 @@ +{{sitename: Nette Τεκμηρίωση}} +{{leftbar: nette:@menu-topics}} diff --git a/bootstrap/en/@home.texy b/bootstrap/en/@home.texy index ba40d2c3f2..202b427f3e 100644 --- a/bootstrap/en/@home.texy +++ b/bootstrap/en/@home.texy @@ -93,7 +93,4 @@ $configurator->addDynamicParameters([ ]); ``` -The `projectId` parameter can be referenced in the configuration using the `%projectId%` notation. - - -{{leftbar: nette:@menu-topics}} +The `remoteIp` parameter can be referenced in the configuration using the `%remoteIp%` notation. diff --git a/bootstrap/en/@meta.texy b/bootstrap/en/@meta.texy new file mode 100644 index 0000000000..91205786e5 --- /dev/null +++ b/bootstrap/en/@meta.texy @@ -0,0 +1,2 @@ +{{sitename: Nette Documentation}} +{{leftbar: nette:@menu-topics}} diff --git a/bootstrap/es/@home.texy b/bootstrap/es/@home.texy index 3e2a2af551..25321bada6 100644 --- a/bootstrap/es/@home.texy +++ b/bootstrap/es/@home.texy @@ -94,6 +94,3 @@ $configurator->addDynamicParameters([ ``` Se puede hacer referencia al parámetro `projectId` en la configuración usando la notación `%projectId%`. - - -{{leftbar: nette:@menu-topics}} diff --git a/bootstrap/es/@meta.texy b/bootstrap/es/@meta.texy new file mode 100644 index 0000000000..25d506cde9 --- /dev/null +++ b/bootstrap/es/@meta.texy @@ -0,0 +1,2 @@ +{{sitename: Nette Documentación}} +{{leftbar: nette:@menu-topics}} diff --git a/bootstrap/fr/@home.texy b/bootstrap/fr/@home.texy index d103bfecab..25f662ac6c 100644 --- a/bootstrap/fr/@home.texy +++ b/bootstrap/fr/@home.texy @@ -94,6 +94,3 @@ $configurator->addDynamicParameters([ ``` Le paramètre `projectId` peut être référencé dans la configuration en utilisant la notation `%projectId%`. - - -{{leftbar: nette:@menu-topics}} diff --git a/bootstrap/fr/@meta.texy b/bootstrap/fr/@meta.texy new file mode 100644 index 0000000000..95ec8a4ef6 --- /dev/null +++ b/bootstrap/fr/@meta.texy @@ -0,0 +1,2 @@ +{{sitename: Documentation Nette}} +{{leftbar: nette:@menu-topics}} diff --git a/bootstrap/hu/@home.texy b/bootstrap/hu/@home.texy index 5f678c7862..86a0ca10df 100644 --- a/bootstrap/hu/@home.texy +++ b/bootstrap/hu/@home.texy @@ -94,6 +94,3 @@ $configurator->addDynamicParameters([ ``` A `projectId` paraméterre a konfigurációban a `%projectId%` jelöléssel hivatkozhatunk. - - -{{leftbar: nette:@menu-topics}} diff --git a/bootstrap/hu/@meta.texy b/bootstrap/hu/@meta.texy new file mode 100644 index 0000000000..c00a2158aa --- /dev/null +++ b/bootstrap/hu/@meta.texy @@ -0,0 +1,2 @@ +{{sitename: Nette dokumentáció}} +{{leftbar: nette:@menu-topics}} diff --git a/bootstrap/it/@home.texy b/bootstrap/it/@home.texy index 010aa00503..72a8b4d1f0 100644 --- a/bootstrap/it/@home.texy +++ b/bootstrap/it/@home.texy @@ -94,6 +94,3 @@ $configurator->addDynamicParameters([ ``` Al parametro `projectId` si può fare riferimento nella configurazione tramite la notazione `%projectId%`. - - -{{leftbar: nette:@menu-topics}} diff --git a/bootstrap/it/@meta.texy b/bootstrap/it/@meta.texy new file mode 100644 index 0000000000..9d19e7312c --- /dev/null +++ b/bootstrap/it/@meta.texy @@ -0,0 +1,2 @@ +{{sitename: Documentazione Nette}} +{{leftbar: nette:@menu-topics}} diff --git a/bootstrap/ja/@home.texy b/bootstrap/ja/@home.texy index 3643ae7ed2..80ea76d567 100644 --- a/bootstrap/ja/@home.texy +++ b/bootstrap/ja/@home.texy @@ -94,6 +94,3 @@ $configurator->addDynamicParameters([ ``` パラメータ `projectId` は、設定内で `%projectId%` と記述することで参照できます。 - - -{{leftbar: nette:@menu-topics}} diff --git a/bootstrap/ja/@meta.texy b/bootstrap/ja/@meta.texy new file mode 100644 index 0000000000..7d67dcb7b8 --- /dev/null +++ b/bootstrap/ja/@meta.texy @@ -0,0 +1,2 @@ +{{sitename: Nette ドキュメンテーション}} +{{leftbar: nette:@menu-topics}} diff --git a/bootstrap/pl/@home.texy b/bootstrap/pl/@home.texy index 4fb23f2d46..5089994f3b 100644 --- a/bootstrap/pl/@home.texy +++ b/bootstrap/pl/@home.texy @@ -94,6 +94,3 @@ $configurator->addDynamicParameters([ ``` Do parametru `projectId` można się odwołać w konfiguracji zapisem `%projectId%`. - - -{{leftbar: nette:@menu-topics}} diff --git a/bootstrap/pl/@meta.texy b/bootstrap/pl/@meta.texy new file mode 100644 index 0000000000..08f2227fb5 --- /dev/null +++ b/bootstrap/pl/@meta.texy @@ -0,0 +1,2 @@ +{{sitename: Dokumentacja Nette}} +{{leftbar: nette:@menu-topics}} diff --git a/bootstrap/pt/@home.texy b/bootstrap/pt/@home.texy index 5ae38a0ce4..0344fc188a 100644 --- a/bootstrap/pt/@home.texy +++ b/bootstrap/pt/@home.texy @@ -94,6 +94,3 @@ $configurator->addDynamicParameters([ ``` O parâmetro `projectId` pode ser referenciado na configuração usando a notação `%projectId%`. - - -{{leftbar: nette:@menu-topics}} diff --git a/bootstrap/pt/@meta.texy b/bootstrap/pt/@meta.texy new file mode 100644 index 0000000000..e2566bcb44 --- /dev/null +++ b/bootstrap/pt/@meta.texy @@ -0,0 +1,2 @@ +{{sitename: Documentação Nette}} +{{leftbar: nette:@menu-topics}} diff --git a/bootstrap/ro/@home.texy b/bootstrap/ro/@home.texy index e1b4c07cf6..16606ee9e5 100644 --- a/bootstrap/ro/@home.texy +++ b/bootstrap/ro/@home.texy @@ -94,6 +94,3 @@ $configurator->addDynamicParameters([ ``` Parametrul `projectId` poate fi referențiat în configurație prin notația `%projectId%`. - - -{{leftbar: nette:@menu-topics}} diff --git a/bootstrap/ro/@meta.texy b/bootstrap/ro/@meta.texy new file mode 100644 index 0000000000..6554692600 --- /dev/null +++ b/bootstrap/ro/@meta.texy @@ -0,0 +1,2 @@ +{{sitename: Documentație Nette}} +{{leftbar: nette:@menu-topics}} diff --git a/bootstrap/ru/@home.texy b/bootstrap/ru/@home.texy index 8b69c4f8de..ec99937fd8 100644 --- a/bootstrap/ru/@home.texy +++ b/bootstrap/ru/@home.texy @@ -94,6 +94,3 @@ $configurator->addDynamicParameters([ ``` На параметр `projectId` можно ссылаться в конфигурации с помощью записи `%projectId%`. - - -{{leftbar: nette:@menu-topics}} diff --git a/bootstrap/ru/@meta.texy b/bootstrap/ru/@meta.texy new file mode 100644 index 0000000000..61577d6323 --- /dev/null +++ b/bootstrap/ru/@meta.texy @@ -0,0 +1,2 @@ +{{sitename: Документация Nette}} +{{leftbar: nette:@menu-topics}} diff --git a/bootstrap/sl/@home.texy b/bootstrap/sl/@home.texy index b7d6c3c107..76641a1cce 100644 --- a/bootstrap/sl/@home.texy +++ b/bootstrap/sl/@home.texy @@ -94,6 +94,3 @@ $configurator->addDynamicParameters([ ``` Na parameter `projectId` se lahko v konfiguraciji sklicujete z zapisom `%projectId%`. - - -{{leftbar: nette:@menu-topics}} diff --git a/bootstrap/sl/@meta.texy b/bootstrap/sl/@meta.texy new file mode 100644 index 0000000000..282883a3d6 --- /dev/null +++ b/bootstrap/sl/@meta.texy @@ -0,0 +1,2 @@ +{{sitename: Nette Dokumentacija}} +{{leftbar: nette:@menu-topics}} diff --git a/bootstrap/tr/@home.texy b/bootstrap/tr/@home.texy index ce17d0d8a1..732122fed8 100644 --- a/bootstrap/tr/@home.texy +++ b/bootstrap/tr/@home.texy @@ -94,6 +94,3 @@ $configurator->addDynamicParameters([ ``` `projectId` parametresine yapılandırmada `%projectId%` yazılarak başvurulabilir. - - -{{leftbar: nette:@menu-topics}} diff --git a/bootstrap/tr/@meta.texy b/bootstrap/tr/@meta.texy new file mode 100644 index 0000000000..e5c5cea355 --- /dev/null +++ b/bootstrap/tr/@meta.texy @@ -0,0 +1,2 @@ +{{sitename: Nette Dokümantasyonu}} +{{leftbar: nette:@menu-topics}} diff --git a/bootstrap/uk/@home.texy b/bootstrap/uk/@home.texy index e62aa8fff2..1320bdf9fa 100644 --- a/bootstrap/uk/@home.texy +++ b/bootstrap/uk/@home.texy @@ -94,6 +94,3 @@ $configurator->addDynamicParameters([ ``` На параметр `projectId` можна посилатися в конфігурації записом `%projectId%`. - - -{{leftbar: nette:@menu-topics}} diff --git a/bootstrap/uk/@meta.texy b/bootstrap/uk/@meta.texy new file mode 100644 index 0000000000..083a8ab9f7 --- /dev/null +++ b/bootstrap/uk/@meta.texy @@ -0,0 +1,2 @@ +{{sitename: Документація Nette}} +{{leftbar: nette:@menu-topics}} diff --git a/caching/bg/@home.texy b/caching/bg/@home.texy index 47c8c206a5..8c04a7e659 100644 --- a/caching/bg/@home.texy +++ b/caching/bg/@home.texy @@ -482,6 +482,3 @@ services: ``` Тази настройка не влияе на кеширането на шаблони в Latte или DI контейнера, тъй като тези библиотеки не използват услугите на nette/caching и управляват кеша си самостоятелно. Техният кеш впрочем [не е необходимо да се изключва |nette:troubleshooting#Как да изключите кеша по време на разработка] в режим на разработка. - - -{{leftbar: nette:@menu-topics}} diff --git a/caching/bg/@meta.texy b/caching/bg/@meta.texy new file mode 100644 index 0000000000..794cbc8522 --- /dev/null +++ b/caching/bg/@meta.texy @@ -0,0 +1,2 @@ +{{sitename: Документация на Nette}} +{{leftbar: nette:@menu-topics}} diff --git a/caching/cs/@home.texy b/caching/cs/@home.texy index 01638b4496..1d3f3eed17 100644 --- a/caching/cs/@home.texy +++ b/caching/cs/@home.texy @@ -125,7 +125,7 @@ Nebo pomocí 3. parametru v metodě `load()`, např: ```php $value = $cache->load($key, function () { - return ...; + return /* ... */; }, [Cache::Expire => '20 minutes']); ``` @@ -293,7 +293,7 @@ Velmi elegantně lze zachytávat a cachovat výstup: ```php if ($capture = $cache->capture($key)) { - echo ... // vypisujeme data + // echo ... vypisujeme data $capture->end(); // uložíme výstup do cache } @@ -482,6 +482,3 @@ services: ``` Toto nastavení nemá vliv na kešování šablon v Latte nebo DI kontejeru, protože tyto knihovny nevyužívají služeb nette/caching a spravují si cache samostatně. Jejich cache ostatně [není potřeba |nette:troubleshooting#Jak vypnout cache během vývoje] ve vývojářském režimu vypínat. - - -{{leftbar: nette:@menu-topics}} diff --git a/caching/cs/@meta.texy b/caching/cs/@meta.texy new file mode 100644 index 0000000000..08edde785b --- /dev/null +++ b/caching/cs/@meta.texy @@ -0,0 +1,2 @@ +{{sitename: Nette Dokumentace}} +{{leftbar: nette:@menu-topics}} diff --git a/caching/de/@home.texy b/caching/de/@home.texy index 07292cfb61..d2c2c5186a 100644 --- a/caching/de/@home.texy +++ b/caching/de/@home.texy @@ -482,6 +482,3 @@ services: ``` Diese Einstellung hat keinen Einfluss auf das Caching von Templates in Latte oder des DI-Containers, da diese Bibliotheken die Dienste von `nette/caching` nicht nutzen und ihren Cache selbst verwalten. Ihr Cache muss im Entwicklermodus übrigens [nicht deaktiviert werden |nette:troubleshooting#Wie schaltet man den Cache während der Entwicklung aus]. - - -{{leftbar: nette:@menu-topics}} diff --git a/caching/de/@meta.texy b/caching/de/@meta.texy new file mode 100644 index 0000000000..2cf383a5cf --- /dev/null +++ b/caching/de/@meta.texy @@ -0,0 +1,2 @@ +{{sitename: Nette Dokumentation}} +{{leftbar: nette:@menu-topics}} diff --git a/caching/el/@home.texy b/caching/el/@home.texy index 2471374f2c..a9c9f774d5 100644 --- a/caching/el/@home.texy +++ b/caching/el/@home.texy @@ -482,6 +482,3 @@ services: ``` Αυτή η ρύθμιση δεν επηρεάζει το caching των προτύπων στο Latte ή τον DI container, καθώς αυτές οι βιβλιοθήκες δεν χρησιμοποιούν τις υπηρεσίες nette/caching και διαχειρίζονται την cache τους ανεξάρτητα. Εξάλλου, η cache τους [δεν χρειάζεται να απενεργοποιηθεί |nette:troubleshooting#Πώς να απενεργοποιήσετε την cache κατά την ανάπτυξη] στη λειτουργία ανάπτυξης. - - -{{leftbar: nette:@menu-topics}} diff --git a/caching/el/@meta.texy b/caching/el/@meta.texy new file mode 100644 index 0000000000..a09ce5fe0d --- /dev/null +++ b/caching/el/@meta.texy @@ -0,0 +1,2 @@ +{{sitename: Nette Τεκμηρίωση}} +{{leftbar: nette:@menu-topics}} diff --git a/caching/en/@home.texy b/caching/en/@home.texy index 8f3f5c102e..e3557a0539 100644 --- a/caching/en/@home.texy +++ b/caching/en/@home.texy @@ -125,7 +125,7 @@ Or by using the 3rd parameter of the `load()` method itself, e.g.: ```php $value = $cache->load($key, function () { - return ...; + return /* ... */; }, [Cache::Expire => '20 minutes']); ``` @@ -293,7 +293,7 @@ Output can be captured and cached very elegantly: ```php if ($capture = $cache->capture($key)) { - echo ... // printing some data + // echo ... printing some data $capture->end(); // save the output to the cache } @@ -482,6 +482,3 @@ services: ``` This setting does not affect the caching of Latte templates or the DI container, as these libraries do not utilize `nette/caching` services and manage their caches independently. Furthermore, their caches [do not typically need to be disabled |nette:troubleshooting#How to Disable Cache During Development] during development mode. - - -{{leftbar: nette:@menu-topics}} diff --git a/caching/en/@meta.texy b/caching/en/@meta.texy new file mode 100644 index 0000000000..91205786e5 --- /dev/null +++ b/caching/en/@meta.texy @@ -0,0 +1,2 @@ +{{sitename: Nette Documentation}} +{{leftbar: nette:@menu-topics}} diff --git a/caching/es/@home.texy b/caching/es/@home.texy index f319d5890b..ce53dca55f 100644 --- a/caching/es/@home.texy +++ b/caching/es/@home.texy @@ -482,6 +482,3 @@ services: ``` Esta configuración no afecta el almacenamiento en caché de plantillas en Latte o el contenedor DI, ya que estas librerías no utilizan los servicios de nette/caching y gestionan su caché de forma independiente. Además, su caché [no necesita ser desactivada |nette:troubleshooting#Cómo desactivar la caché durante el desarrollo] en el modo de desarrollo. - - -{{leftbar: nette:@menu-topics}} diff --git a/caching/es/@meta.texy b/caching/es/@meta.texy new file mode 100644 index 0000000000..25d506cde9 --- /dev/null +++ b/caching/es/@meta.texy @@ -0,0 +1,2 @@ +{{sitename: Nette Documentación}} +{{leftbar: nette:@menu-topics}} diff --git a/caching/fr/@home.texy b/caching/fr/@home.texy index cc0f5d5e81..f0dabcdc54 100644 --- a/caching/fr/@home.texy +++ b/caching/fr/@home.texy @@ -482,6 +482,3 @@ services: ``` Ce paramètre n'affecte pas la mise en cache des templates dans Latte ou du conteneur DI, car ces bibliothèques n'utilisent pas les services nette/caching et gèrent leur propre cache indépendamment. D'ailleurs, leur cache [n'a pas besoin d'être désactivé |nette:troubleshooting#Comment désactiver le cache pendant le développement] en mode développeur. - - -{{leftbar: nette:@menu-topics}} diff --git a/caching/fr/@meta.texy b/caching/fr/@meta.texy new file mode 100644 index 0000000000..95ec8a4ef6 --- /dev/null +++ b/caching/fr/@meta.texy @@ -0,0 +1,2 @@ +{{sitename: Documentation Nette}} +{{leftbar: nette:@menu-topics}} diff --git a/caching/hu/@home.texy b/caching/hu/@home.texy index f9f4a3d4b5..25518b3721 100644 --- a/caching/hu/@home.texy +++ b/caching/hu/@home.texy @@ -482,6 +482,3 @@ services: ``` Ez a beállítás nincs hatással a sablonok gyorsítótárazására a Latte-ban vagy a DI konténerben, mivel ezek a könyvtárak nem használják a nette/caching szolgáltatásait, és önállóan kezelik a cache-t. Egyébként a cache-üket [nem szükséges kikapcsolni |nette:troubleshooting#Hogyan kapcsoljuk ki a cache-t fejlesztés közben] fejlesztői módban. - - -{{leftbar: nette:@menu-topics}} diff --git a/caching/hu/@meta.texy b/caching/hu/@meta.texy new file mode 100644 index 0000000000..c00a2158aa --- /dev/null +++ b/caching/hu/@meta.texy @@ -0,0 +1,2 @@ +{{sitename: Nette dokumentáció}} +{{leftbar: nette:@menu-topics}} diff --git a/caching/it/@home.texy b/caching/it/@home.texy index f09ff05ce4..3b9e0dba0b 100644 --- a/caching/it/@home.texy +++ b/caching/it/@home.texy @@ -482,6 +482,3 @@ services: ``` Questa impostazione non influisce sulla cache dei template in Latte o del container DI, poiché queste librerie non utilizzano i servizi di nette/caching e gestiscono la cache autonomamente. La loro cache, del resto, [non è necessario disattivare |nette:troubleshooting#Come disattivare la cache durante lo sviluppo] in modalità sviluppatore. - - -{{leftbar: nette:@menu-topics}} diff --git a/caching/it/@meta.texy b/caching/it/@meta.texy new file mode 100644 index 0000000000..9d19e7312c --- /dev/null +++ b/caching/it/@meta.texy @@ -0,0 +1,2 @@ +{{sitename: Documentazione Nette}} +{{leftbar: nette:@menu-topics}} diff --git a/caching/ja/@home.texy b/caching/ja/@home.texy index a7403892a4..50ae8d3d98 100644 --- a/caching/ja/@home.texy +++ b/caching/ja/@home.texy @@ -482,6 +482,3 @@ services: ``` この設定は、LatteのテンプレートやDIコンテナのキャッシュには影響しません。これらのライブラリはnette/cachingサービスを使用せず、独自のキャッシュを管理するためです。また、開発モードでは[これらのキャッシュを無効にする必要はありません |nette:troubleshooting#開発中にキャッシュを無効にする方法は]。 - - -{{leftbar: nette:@menu-topics}} diff --git a/caching/ja/@meta.texy b/caching/ja/@meta.texy new file mode 100644 index 0000000000..7d67dcb7b8 --- /dev/null +++ b/caching/ja/@meta.texy @@ -0,0 +1,2 @@ +{{sitename: Nette ドキュメンテーション}} +{{leftbar: nette:@menu-topics}} diff --git a/caching/pl/@home.texy b/caching/pl/@home.texy index d24055b70a..61fdbc3275 100644 --- a/caching/pl/@home.texy +++ b/caching/pl/@home.texy @@ -482,6 +482,3 @@ services: ``` To ustawienie nie ma wpływu na buforowanie szablonów w Latte ani kontenera DI, ponieważ te biblioteki nie korzystają z usług `nette/caching` i zarządzają swoją pamięcią podręczną samodzielnie. Ich cache zresztą [nie trzeba wyłączać |nette:troubleshooting#Jak wyłączyć cache podczas developmentu] w trybie deweloperskim. - - -{{leftbar: nette:@menu-topics}} diff --git a/caching/pl/@meta.texy b/caching/pl/@meta.texy new file mode 100644 index 0000000000..08f2227fb5 --- /dev/null +++ b/caching/pl/@meta.texy @@ -0,0 +1,2 @@ +{{sitename: Dokumentacja Nette}} +{{leftbar: nette:@menu-topics}} diff --git a/caching/pt/@home.texy b/caching/pt/@home.texy index 09db0caa9f..82c8cbb29f 100644 --- a/caching/pt/@home.texy +++ b/caching/pt/@home.texy @@ -482,6 +482,3 @@ services: ``` Esta configuração não afeta o armazenamento em cache de templates no Latte ou no contêiner DI, pois essas bibliotecas não usam os serviços nette/caching e gerenciam sua própria cache de forma independente. Afinal, a cache delas [não precisa ser desativada |nette:troubleshooting#Como desativar o cache durante o desenvolvimento] no modo de desenvolvimento. - - -{{leftbar: nette:@menu-topics}} diff --git a/caching/pt/@meta.texy b/caching/pt/@meta.texy new file mode 100644 index 0000000000..e2566bcb44 --- /dev/null +++ b/caching/pt/@meta.texy @@ -0,0 +1,2 @@ +{{sitename: Documentação Nette}} +{{leftbar: nette:@menu-topics}} diff --git a/caching/ro/@home.texy b/caching/ro/@home.texy index ec5ba3934d..2bff23a31e 100644 --- a/caching/ro/@home.texy +++ b/caching/ro/@home.texy @@ -482,6 +482,3 @@ services: ``` Această setare nu afectează stocarea în cache a șabloanelor în Latte sau a containerului DI, deoarece aceste biblioteci nu utilizează serviciile nette/caching și își gestionează cache-ul independent. Cache-ul lor, de altfel, [nu trebuie dezactivat |nette:troubleshooting#Cum să dezactivați cache-ul în timpul dezvoltării] în modul dezvoltator. - - -{{leftbar: nette:@menu-topics}} diff --git a/caching/ro/@meta.texy b/caching/ro/@meta.texy new file mode 100644 index 0000000000..6554692600 --- /dev/null +++ b/caching/ro/@meta.texy @@ -0,0 +1,2 @@ +{{sitename: Documentație Nette}} +{{leftbar: nette:@menu-topics}} diff --git a/caching/ru/@home.texy b/caching/ru/@home.texy index ce84fe07e3..784e86d219 100644 --- a/caching/ru/@home.texy +++ b/caching/ru/@home.texy @@ -482,6 +482,3 @@ services: ``` Эта настройка не влияет на кеширование шаблонов в Latte или DI-контейнера, поскольку эти библиотеки не используют сервисы nette/caching и управляют своим кешем самостоятельно. Их кеш, впрочем, [нет необходимости |nette:troubleshooting#Как отключить кеш во время разработки] отключать в режиме разработки. - - -{{leftbar: nette:@menu-topics}} diff --git a/caching/ru/@meta.texy b/caching/ru/@meta.texy new file mode 100644 index 0000000000..61577d6323 --- /dev/null +++ b/caching/ru/@meta.texy @@ -0,0 +1,2 @@ +{{sitename: Документация Nette}} +{{leftbar: nette:@menu-topics}} diff --git a/caching/sl/@home.texy b/caching/sl/@home.texy index f7bb73edc5..f87e7a5f6e 100644 --- a/caching/sl/@home.texy +++ b/caching/sl/@home.texy @@ -482,6 +482,3 @@ services: ``` Ta nastavitev nima vpliva na predpomnjenje predlog v Latte ali DI vsebnika, ker te knjižnice ne uporabljajo storitev nette/caching in si upravljajo predpomnilnik samostojno. Njihovega predpomnilnika sicer [ni treba |nette:troubleshooting#Kako izklopiti predpomnilnik med razvojem] v razvojnem načinu izklapljati. - - -{{leftbar: nette:@menu-topics}} diff --git a/caching/sl/@meta.texy b/caching/sl/@meta.texy new file mode 100644 index 0000000000..282883a3d6 --- /dev/null +++ b/caching/sl/@meta.texy @@ -0,0 +1,2 @@ +{{sitename: Nette Dokumentacija}} +{{leftbar: nette:@menu-topics}} diff --git a/caching/tr/@home.texy b/caching/tr/@home.texy index e4b0c8ea71..a14067b97e 100644 --- a/caching/tr/@home.texy +++ b/caching/tr/@home.texy @@ -482,6 +482,3 @@ services: ``` Bu ayarın Latte'deki şablonların veya DI konteynerinin önbelleğe alınması üzerinde bir etkisi yoktur, çünkü bu kütüphaneler nette/caching servislerini kullanmaz ve kendi önbelleklerini yönetirler. Ayrıca, geliştirme modunda [önbelleklerini devre dışı bırakmaya gerek yoktur |nette:troubleshooting#Geliştirme Sırasında Önbellek Nasıl Kapatılır]. - - -{{leftbar: nette:@menu-topics}} diff --git a/caching/tr/@meta.texy b/caching/tr/@meta.texy new file mode 100644 index 0000000000..e5c5cea355 --- /dev/null +++ b/caching/tr/@meta.texy @@ -0,0 +1,2 @@ +{{sitename: Nette Dokümantasyonu}} +{{leftbar: nette:@menu-topics}} diff --git a/caching/uk/@home.texy b/caching/uk/@home.texy index 6847d378ba..14e19a212f 100644 --- a/caching/uk/@home.texy +++ b/caching/uk/@home.texy @@ -482,6 +482,3 @@ services: ``` Це налаштування не впливає на кешування шаблонів у Latte або DI-контейнера, оскільки ці бібліотеки не використовують сервіси nette/caching і керують своїм кешем самостійно. Їхній кеш, до речі, [не потрібно |nette:troubleshooting#Як вимкнути кеш під час розробки] вимикати в режимі розробки. - - -{{leftbar: nette:@menu-topics}} diff --git a/caching/uk/@meta.texy b/caching/uk/@meta.texy new file mode 100644 index 0000000000..083a8ab9f7 --- /dev/null +++ b/caching/uk/@meta.texy @@ -0,0 +1,2 @@ +{{sitename: Документація Nette}} +{{leftbar: nette:@menu-topics}} diff --git a/component-model/bg/@home.texy b/component-model/bg/@home.texy index f873252424..2209fed3e8 100644 --- a/component-model/bg/@home.texy +++ b/component-model/bg/@home.texy @@ -65,6 +65,3 @@ class UploadControl extends Nette\Forms\Controls\BaseControl ``` и щом формата е налична, се извиква callback. (Преди това вместо него се използваха общите методи `attached`, респ. `detached`). - - -{{leftbar: nette:@menu-topics}} diff --git a/component-model/bg/@meta.texy b/component-model/bg/@meta.texy new file mode 100644 index 0000000000..794cbc8522 --- /dev/null +++ b/component-model/bg/@meta.texy @@ -0,0 +1,2 @@ +{{sitename: Документация на Nette}} +{{leftbar: nette:@menu-topics}} diff --git a/component-model/cs/@home.texy b/component-model/cs/@home.texy index 1a80e31100..7aa17b402f 100644 --- a/component-model/cs/@home.texy +++ b/component-model/cs/@home.texy @@ -65,6 +65,3 @@ class UploadControl extends Nette\Forms\Controls\BaseControl ``` a jakmile je formulář k dispozici, zavolá se callback. (Dříve se místo něj používala společná metoda `attached` resp. `detached`). - - -{{leftbar: nette:@menu-topics}} diff --git a/component-model/cs/@meta.texy b/component-model/cs/@meta.texy new file mode 100644 index 0000000000..08edde785b --- /dev/null +++ b/component-model/cs/@meta.texy @@ -0,0 +1,2 @@ +{{sitename: Nette Dokumentace}} +{{leftbar: nette:@menu-topics}} diff --git a/component-model/de/@home.texy b/component-model/de/@home.texy index 20251ac43e..680880c8f3 100644 --- a/component-model/de/@home.texy +++ b/component-model/de/@home.texy @@ -65,6 +65,3 @@ class UploadControl extends Nette\Forms\Controls\BaseControl ``` und sobald das Formular verfügbar ist, wird der Callback aufgerufen. (Früher wurde stattdessen die gemeinsame Methode `attached` bzw. `detached` verwendet). - - -{{leftbar: nette:@menu-topics}} diff --git a/component-model/de/@meta.texy b/component-model/de/@meta.texy new file mode 100644 index 0000000000..2cf383a5cf --- /dev/null +++ b/component-model/de/@meta.texy @@ -0,0 +1,2 @@ +{{sitename: Nette Dokumentation}} +{{leftbar: nette:@menu-topics}} diff --git a/component-model/el/@home.texy b/component-model/el/@home.texy index ecf747d215..b38ccc1262 100644 --- a/component-model/el/@home.texy +++ b/component-model/el/@home.texy @@ -65,6 +65,3 @@ class UploadControl extends Nette\Forms\Controls\BaseControl ``` και μόλις η φόρμα είναι διαθέσιμη, καλείται το callback. (Παλαιότερα, χρησιμοποιούνταν αντί αυτού η κοινή μέθοδος `attached` ή `detached`). - - -{{leftbar: nette:@menu-topics}} diff --git a/component-model/el/@meta.texy b/component-model/el/@meta.texy new file mode 100644 index 0000000000..a09ce5fe0d --- /dev/null +++ b/component-model/el/@meta.texy @@ -0,0 +1,2 @@ +{{sitename: Nette Τεκμηρίωση}} +{{leftbar: nette:@menu-topics}} diff --git a/component-model/en/@home.texy b/component-model/en/@home.texy index ccfd4f05a4..ec18f76c32 100644 --- a/component-model/en/@home.texy +++ b/component-model/en/@home.texy @@ -65,6 +65,3 @@ class UploadControl extends Nette\Forms\Controls\BaseControl ``` and as soon as the form becomes available, the callback is invoked. (Previously, the common methods `attached` and `detached` were used for this purpose.) - - -{{leftbar: nette:@menu-topics}} diff --git a/component-model/en/@meta.texy b/component-model/en/@meta.texy new file mode 100644 index 0000000000..91205786e5 --- /dev/null +++ b/component-model/en/@meta.texy @@ -0,0 +1,2 @@ +{{sitename: Nette Documentation}} +{{leftbar: nette:@menu-topics}} diff --git a/component-model/es/@home.texy b/component-model/es/@home.texy index 1c272b7f46..515782fc79 100644 --- a/component-model/es/@home.texy +++ b/component-model/es/@home.texy @@ -65,6 +65,3 @@ class UploadControl extends Nette\Forms\Controls\BaseControl ``` y tan pronto como el formulario esté disponible, se llama al callback. (Anteriormente, se usaba el método común `attached` o `detached` en su lugar). - - -{{leftbar: nette:@menu-topics}} diff --git a/component-model/es/@meta.texy b/component-model/es/@meta.texy new file mode 100644 index 0000000000..25d506cde9 --- /dev/null +++ b/component-model/es/@meta.texy @@ -0,0 +1,2 @@ +{{sitename: Nette Documentación}} +{{leftbar: nette:@menu-topics}} diff --git a/component-model/fr/@home.texy b/component-model/fr/@home.texy index fd91689007..706b8f46ce 100644 --- a/component-model/fr/@home.texy +++ b/component-model/fr/@home.texy @@ -65,6 +65,3 @@ class UploadControl extends Nette\Forms\Controls\BaseControl ``` et dès que le formulaire est disponible, le callback est appelé. (Auparavant, les méthodes communes `attached` ou `detached` étaient utilisées à la place). - - -{{leftbar: nette:@menu-topics}} diff --git a/component-model/fr/@meta.texy b/component-model/fr/@meta.texy new file mode 100644 index 0000000000..95ec8a4ef6 --- /dev/null +++ b/component-model/fr/@meta.texy @@ -0,0 +1,2 @@ +{{sitename: Documentation Nette}} +{{leftbar: nette:@menu-topics}} diff --git a/component-model/hu/@home.texy b/component-model/hu/@home.texy index 965977e0d3..5ea05ef999 100644 --- a/component-model/hu/@home.texy +++ b/component-model/hu/@home.texy @@ -65,6 +65,3 @@ class UploadControl extends Nette\Forms\Controls\BaseControl ``` és amint az űrlap elérhetővé válik, a callback meghívódik. (Korábban helyette a közös `attached`, illetve `detached` metódust használták). - - -{{leftbar: nette:@menu-topics}} diff --git a/component-model/hu/@meta.texy b/component-model/hu/@meta.texy new file mode 100644 index 0000000000..c00a2158aa --- /dev/null +++ b/component-model/hu/@meta.texy @@ -0,0 +1,2 @@ +{{sitename: Nette dokumentáció}} +{{leftbar: nette:@menu-topics}} diff --git a/component-model/it/@home.texy b/component-model/it/@home.texy index df5f1609c0..77d7b09509 100644 --- a/component-model/it/@home.texy +++ b/component-model/it/@home.texy @@ -65,6 +65,3 @@ class UploadControl extends Nette\Forms\Controls\BaseControl ``` e non appena il form è disponibile, viene chiamato il callback. (In passato, al suo posto venivano usati i metodi comuni `attached` rispettivamente `detached`). - - -{{leftbar: nette:@menu-topics}} diff --git a/component-model/it/@meta.texy b/component-model/it/@meta.texy new file mode 100644 index 0000000000..9d19e7312c --- /dev/null +++ b/component-model/it/@meta.texy @@ -0,0 +1,2 @@ +{{sitename: Documentazione Nette}} +{{leftbar: nette:@menu-topics}} diff --git a/component-model/ja/@home.texy b/component-model/ja/@home.texy index 75e45c019e..6f62c85626 100644 --- a/component-model/ja/@home.texy +++ b/component-model/ja/@home.texy @@ -65,6 +65,3 @@ class UploadControl extends Nette\Forms\Controls\BaseControl ``` そして、フォームが利用可能になるとすぐに、コールバックが呼び出されます。(以前は、代わりに共通のメソッド `attached` または `detached` が使用されていました)。 - - -{{leftbar: nette:@menu-topics}} diff --git a/component-model/ja/@meta.texy b/component-model/ja/@meta.texy new file mode 100644 index 0000000000..7d67dcb7b8 --- /dev/null +++ b/component-model/ja/@meta.texy @@ -0,0 +1,2 @@ +{{sitename: Nette ドキュメンテーション}} +{{leftbar: nette:@menu-topics}} diff --git a/component-model/pl/@home.texy b/component-model/pl/@home.texy index cd145ddecf..b20f94a1f3 100644 --- a/component-model/pl/@home.texy +++ b/component-model/pl/@home.texy @@ -65,6 +65,3 @@ class UploadControl extends Nette\Forms\Controls\BaseControl ``` a gdy formularz jest dostępny, wywoływany jest callback. (Wcześniej zamiast niego używano wspólnej metody `attached` lub `detached`). - - -{{leftbar: nette:@menu-topics}} diff --git a/component-model/pl/@meta.texy b/component-model/pl/@meta.texy new file mode 100644 index 0000000000..08f2227fb5 --- /dev/null +++ b/component-model/pl/@meta.texy @@ -0,0 +1,2 @@ +{{sitename: Dokumentacja Nette}} +{{leftbar: nette:@menu-topics}} diff --git a/component-model/pt/@home.texy b/component-model/pt/@home.texy index 95ddee0a42..2e57ace611 100644 --- a/component-model/pt/@home.texy +++ b/component-model/pt/@home.texy @@ -65,6 +65,3 @@ class UploadControl extends Nette\Forms\Controls\BaseControl ``` e assim que o formulário estiver disponível, o callback é chamado. (Anteriormente, os métodos comuns `attached` e `detached` eram usados em seu lugar). - - -{{leftbar: nette:@menu-topics}} diff --git a/component-model/pt/@meta.texy b/component-model/pt/@meta.texy new file mode 100644 index 0000000000..e2566bcb44 --- /dev/null +++ b/component-model/pt/@meta.texy @@ -0,0 +1,2 @@ +{{sitename: Documentação Nette}} +{{leftbar: nette:@menu-topics}} diff --git a/component-model/ro/@home.texy b/component-model/ro/@home.texy index 48b9bd6a3f..6bf15157b2 100644 --- a/component-model/ro/@home.texy +++ b/component-model/ro/@home.texy @@ -65,6 +65,3 @@ class UploadControl extends Nette\Forms\Controls\BaseControl ``` și de îndată ce formularul este disponibil, se apelează callback-ul. (Anterior, în locul său se folosea metoda comună `attached` respectiv `detached`). - - -{{leftbar: nette:@menu-topics}} diff --git a/component-model/ro/@meta.texy b/component-model/ro/@meta.texy new file mode 100644 index 0000000000..6554692600 --- /dev/null +++ b/component-model/ro/@meta.texy @@ -0,0 +1,2 @@ +{{sitename: Documentație Nette}} +{{leftbar: nette:@menu-topics}} diff --git a/component-model/ru/@home.texy b/component-model/ru/@home.texy index e913d4f1a3..2b89ffd9fb 100644 --- a/component-model/ru/@home.texy +++ b/component-model/ru/@home.texy @@ -65,6 +65,3 @@ class UploadControl extends Nette\Forms\Controls\BaseControl ``` и как только форма становится доступной, вызывается callback. (Раньше вместо него использовался общий метод `attached` соответственно `detached`). - - -{{leftbar: nette:@menu-topics}} diff --git a/component-model/ru/@meta.texy b/component-model/ru/@meta.texy new file mode 100644 index 0000000000..61577d6323 --- /dev/null +++ b/component-model/ru/@meta.texy @@ -0,0 +1,2 @@ +{{sitename: Документация Nette}} +{{leftbar: nette:@menu-topics}} diff --git a/component-model/sl/@home.texy b/component-model/sl/@home.texy index f9804ff454..cc2bd1f48c 100644 --- a/component-model/sl/@home.texy +++ b/component-model/sl/@home.texy @@ -65,6 +65,3 @@ class UploadControl extends Nette\Forms\Controls\BaseControl ``` in takoj ko je obrazec na voljo, se pokliče povratni klic. (Prej se je namesto njega uporabljala skupna metoda `attached` oz. `detached`). - - -{{leftbar: nette:@menu-topics}} diff --git a/component-model/sl/@meta.texy b/component-model/sl/@meta.texy new file mode 100644 index 0000000000..282883a3d6 --- /dev/null +++ b/component-model/sl/@meta.texy @@ -0,0 +1,2 @@ +{{sitename: Nette Dokumentacija}} +{{leftbar: nette:@menu-topics}} diff --git a/component-model/tr/@home.texy b/component-model/tr/@home.texy index 227f2b35c1..8b8015cab4 100644 --- a/component-model/tr/@home.texy +++ b/component-model/tr/@home.texy @@ -65,6 +65,3 @@ class UploadControl extends Nette\Forms\Controls\BaseControl ``` ve form kullanılabilir olduğunda, geri çağrı çağrılır. (Daha önce bunun yerine ortak `attached` veya `detached` yöntemi kullanılıyordu). - - -{{leftbar: nette:@menu-topics}} diff --git a/component-model/tr/@meta.texy b/component-model/tr/@meta.texy new file mode 100644 index 0000000000..e5c5cea355 --- /dev/null +++ b/component-model/tr/@meta.texy @@ -0,0 +1,2 @@ +{{sitename: Nette Dokümantasyonu}} +{{leftbar: nette:@menu-topics}} diff --git a/component-model/uk/@home.texy b/component-model/uk/@home.texy index 9b9ac7c257..34b27ba85e 100644 --- a/component-model/uk/@home.texy +++ b/component-model/uk/@home.texy @@ -65,6 +65,3 @@ class UploadControl extends Nette\Forms\Controls\BaseControl ``` і як тільки форма стає доступною, викликається callback. (Раніше замість нього використовувалися спільні методи `attached` або `detached`). - - -{{leftbar: nette:@menu-topics}} diff --git a/component-model/uk/@meta.texy b/component-model/uk/@meta.texy new file mode 100644 index 0000000000..083a8ab9f7 --- /dev/null +++ b/component-model/uk/@meta.texy @@ -0,0 +1,2 @@ +{{sitename: Документація Nette}} +{{leftbar: nette:@menu-topics}} diff --git a/contributing/bg/syntax.texy b/contributing/bg/syntax.texy index 23db082cf4..94bbb02a7a 100644 --- a/contributing/bg/syntax.texy +++ b/contributing/bg/syntax.texy @@ -1,7 +1,7 @@ Синтаксис на документацията *************************** -Документацията използва Markdown & [синтаксис на Texy |https://texy.info/cs/syntax] с някои разширения. +Документацията използва Markdown & [синтаксис на Texy |https://texy.nette.org/syntax] с някои разширения. Връзки diff --git a/contributing/cs/coding-standard.texy b/contributing/cs/coding-standard.texy index d9e3cc8c85..5bac29274f 100644 --- a/contributing/cs/coding-standard.texy +++ b/contributing/cs/coding-standard.texy @@ -14,7 +14,7 @@ Obecná pravidla - Dva prázdné řádky se používají k oddělení metod pro lepší čitelnost. - Důvod použití shut-up operátoru musí být zdokumentován: `@mkdir($dir); // @ - adresář může existovat`. - Pokud je použit slabě typizovaný operátor porovnání (tj. `==`, `!=`, ...), musí být zdokumentován záměr: `// == přijmout null` -- Do jednoho souboru `exceptions.php` můžete zapsat více výjimek. +- Do jednoho souboru `exceptions.php` můžete zapsat více výjimek, do souboru `enums.php` více enumů. - U rozhraní se nespecifikuje viditelnost metod, protože jsou vždy veřejné. - Každá property, návratová hodnota a parametr musí mít uvedený typ. Naopak u finálních konstant typ nikdy neuvádíme, protože je zjevný. - K ohraničení řetězce by se měly používat jednoduché uvozovky, s výjimkou případů, kdy samotný literál obsahuje apostrofy. @@ -109,6 +109,23 @@ public function find(string $dir, array $options): array ``` +Globální funkce a konstanty +=========================== + +Globální funkce a konstanty se píší bez úvodního zpětného lomítka, tedy `count($arr)` nikoliv `\count($arr)`. Pro funkce, které umí PHP optimalizovat, uvedeme na začátku souboru `use function`, aby je kompilátor mohl přeložit efektivněji. Jedná se zejména o funkce jako `count`, `strlen`, `is_array`, `is_string`, `is_scalar`, `sprintf` aj. Funkce se uvádějí na jednom řádku, aby úvodní blok importů nebyl zbytečně velký: + +```php +use Nette; +use function count, is_array, is_scalar, sprintf; +``` + +Výjimečně takto uvádíme i konstanty, u kterých může znalost hodnoty posloužit kompilátoru: + +```php +use const PHP_OS_FAMILY; +``` + + Tabulátory místo mezer ====================== diff --git a/contributing/cs/syntax.texy b/contributing/cs/syntax.texy index ad8f3ea4c1..039f8c32ac 100644 --- a/contributing/cs/syntax.texy +++ b/contributing/cs/syntax.texy @@ -1,7 +1,7 @@ Dokumentační syntax ******************* -Dokumentace používá Markdown & [Texy syntaxi |https://texy.info/cs/syntax] s některými rozšířeními. +Dokumentace používá Markdown & [Texy syntaxi |https://texy.nette.org/syntax] s některými rozšířeními. Odkazy diff --git a/contributing/de/syntax.texy b/contributing/de/syntax.texy index 64257e971f..02b8af3554 100644 --- a/contributing/de/syntax.texy +++ b/contributing/de/syntax.texy @@ -1,7 +1,7 @@ Dokumentationssyntax ******************** -Die Dokumentation verwendet Markdown & [Texy-Syntax |https://texy.info/de/syntax] mit einigen Erweiterungen. +Die Dokumentation verwendet Markdown & [Texy-Syntax |https://texy.nette.org/syntax] mit einigen Erweiterungen. Links diff --git a/contributing/el/syntax.texy b/contributing/el/syntax.texy index 8727317430..2f46730e28 100644 --- a/contributing/el/syntax.texy +++ b/contributing/el/syntax.texy @@ -1,7 +1,7 @@ Σύνταξη Τεκμηρίωσης ******************* -Η τεκμηρίωση χρησιμοποιεί Markdown & [σύνταξη Texy |https://texy.info/cs/syntax] με ορισμένες επεκτάσεις. +Η τεκμηρίωση χρησιμοποιεί Markdown & [σύνταξη Texy |https://texy.nette.org/syntax] με ορισμένες επεκτάσεις. Σύνδεσμοι diff --git a/contributing/en/coding-standard.texy b/contributing/en/coding-standard.texy index e98f821d4d..2883d9634d 100644 --- a/contributing/en/coding-standard.texy +++ b/contributing/en/coding-standard.texy @@ -14,7 +14,7 @@ General Rules - Two empty lines are used to separate methods for better readability - The reason for using the shut-up operator (`@`) must be documented: `@mkdir($dir); // @ - directory may exist` - If a weak typed comparison operator is used (i.e., `==`, `!=`, ...), the intention must be documented: `// == to accept null` -- You can write multiple exception classes into a single file named `exceptions.php` +- You can write multiple exception classes into a single file named `exceptions.php`, and multiple enums into `enums.php` - The visibility of methods is not specified for interfaces because they are always public - Each property, return value, and parameter must have a type specified. Conversely, for final constants, we never specify the type because it is obvious - Single quotes should be used to delimit strings, except when the literal itself contains apostrophes @@ -109,6 +109,23 @@ public function find(string $dir, array $options): array ``` +Global Functions and Constants +============================== + +Global functions and constants are written without a leading backslash, i.e., `count($arr)` not `\count($arr)`. For functions that PHP can optimize, add `use function` at the beginning of the file so the compiler can translate them more efficiently. These include functions like `count`, `strlen`, `is_array`, `is_string`, `is_scalar`, `sprintf`, etc. Functions are listed on a single line to keep the import block compact: + +```php +use Nette; +use function count, is_array, is_scalar, sprintf; +``` + +Occasionally, we also import constants whose value knowledge may help the compiler: + +```php +use const PHP_OS_FAMILY; +``` + + Tabs Instead of Spaces ====================== diff --git a/contributing/en/syntax.texy b/contributing/en/syntax.texy index a04894a8b9..c7d81ac54f 100644 --- a/contributing/en/syntax.texy +++ b/contributing/en/syntax.texy @@ -1,7 +1,7 @@ Documentation Syntax ******************** -Documentation uses Markdown & [Texy syntax |https://texy.info/en/syntax] with several enhancements. +Documentation uses Markdown & [Texy syntax |https://texy.nette.org/syntax] with several enhancements. Links diff --git a/contributing/es/syntax.texy b/contributing/es/syntax.texy index 97d8316c1c..559dc80217 100644 --- a/contributing/es/syntax.texy +++ b/contributing/es/syntax.texy @@ -1,7 +1,7 @@ Sintaxis de la documentación **************************** -La documentación utiliza Markdown y la [sintaxis Texy |https://texy.info/cs/syntax] con algunas extensiones. +La documentación utiliza Markdown y la [sintaxis Texy |https://texy.nette.org/syntax] con algunas extensiones. Enlaces diff --git a/contributing/fr/syntax.texy b/contributing/fr/syntax.texy index 29c724851e..9b6df676f7 100644 --- a/contributing/fr/syntax.texy +++ b/contributing/fr/syntax.texy @@ -1,7 +1,7 @@ Syntaxe de la documentation *************************** -La documentation utilise Markdown & la [syntaxe Texy |https://texy.info/cs/syntax] avec quelques extensions. +La documentation utilise Markdown & la [syntaxe Texy |https://texy.nette.org/syntax] avec quelques extensions. Liens diff --git a/contributing/hu/syntax.texy b/contributing/hu/syntax.texy index 66b8b50260..11e46f6417 100644 --- a/contributing/hu/syntax.texy +++ b/contributing/hu/syntax.texy @@ -1,7 +1,7 @@ Dokumentációs szintaxis *********************** -A dokumentáció Markdown & [Texy szintaxist |https://texy.info/cs/syntax] használ néhány kiterjesztéssel. +A dokumentáció Markdown & [Texy szintaxist |https://texy.nette.org/syntax] használ néhány kiterjesztéssel. Linkek diff --git a/contributing/it/syntax.texy b/contributing/it/syntax.texy index ef704f10e4..c60a00fb10 100644 --- a/contributing/it/syntax.texy +++ b/contributing/it/syntax.texy @@ -1,7 +1,7 @@ Sintassi della documentazione ***************************** -La documentazione utilizza Markdown e la [sintassi Texy |https://texy.info/cs/syntax] con alcune estensioni. +La documentazione utilizza Markdown e la [sintassi Texy |https://texy.nette.org/syntax] con alcune estensioni. Link diff --git a/contributing/ja/syntax.texy b/contributing/ja/syntax.texy index 4ee286ef64..2fe4e0c515 100644 --- a/contributing/ja/syntax.texy +++ b/contributing/ja/syntax.texy @@ -1,7 +1,7 @@ ドキュメント構文 ******** -ドキュメントはMarkdownと [Texy構文 |https://texy.info/cs/syntax] を使用し、いくつかの拡張機能があります。 +ドキュメントはMarkdownと [Texy構文 |https://texy.nette.org/syntax] を使用し、いくつかの拡張機能があります。 リンク diff --git a/contributing/pl/syntax.texy b/contributing/pl/syntax.texy index 0090da8000..08b4227f42 100644 --- a/contributing/pl/syntax.texy +++ b/contributing/pl/syntax.texy @@ -1,7 +1,7 @@ Składnia dokumentacji ********************* -Dokumentacja używa składni Markdown & [składni Texy |https://texy.info/cs/syntax] z niektórymi rozszerzeniami. +Dokumentacja używa składni Markdown & [składni Texy |https://texy.nette.org/syntax] z niektórymi rozszerzeniami. Linki diff --git a/contributing/pt/syntax.texy b/contributing/pt/syntax.texy index c820a98389..e810926f67 100644 --- a/contributing/pt/syntax.texy +++ b/contributing/pt/syntax.texy @@ -1,7 +1,7 @@ Sintaxe da Documentação *********************** -A documentação usa Markdown e a [sintaxe Texy |https://texy.info/cs/syntax] com algumas extensões. +A documentação usa Markdown e a [sintaxe Texy |https://texy.nette.org/syntax] com algumas extensões. Links diff --git a/contributing/ro/syntax.texy b/contributing/ro/syntax.texy index dd1a95cf97..d756e4e2b0 100644 --- a/contributing/ro/syntax.texy +++ b/contributing/ro/syntax.texy @@ -1,7 +1,7 @@ Sintaxa documentației ********************* -Documentația utilizează Markdown & [sintaxa Texy |https://texy.info/en/syntax] cu unele extensii. +Documentația utilizează Markdown & [sintaxa Texy |https://texy.nette.org/syntax] cu unele extensii. Linkuri diff --git a/contributing/ru/syntax.texy b/contributing/ru/syntax.texy index ad1bbc8511..af9411a740 100644 --- a/contributing/ru/syntax.texy +++ b/contributing/ru/syntax.texy @@ -1,7 +1,7 @@ Синтаксис документации ********************** -Документация использует синтаксис Markdown и [синтаксис Texy |https://texy.info/cs/syntax] с некоторыми расширениями. +Документация использует синтаксис Markdown и [синтаксис Texy |https://texy.nette.org/syntax] с некоторыми расширениями. Ссылки diff --git a/contributing/sl/syntax.texy b/contributing/sl/syntax.texy index 8486f3ea0e..55aed5ac18 100644 --- a/contributing/sl/syntax.texy +++ b/contributing/sl/syntax.texy @@ -1,7 +1,7 @@ Sintaksa dokumentacije ********************** -Dokumentacija uporablja Markdown & [sintakso Texy |https://texy.info/sl/syntax] z nekaterimi razširitvami. +Dokumentacija uporablja Markdown & [sintakso Texy |https://texy.nette.org/syntax] z nekaterimi razširitvami. Povezave diff --git a/contributing/tr/syntax.texy b/contributing/tr/syntax.texy index 650cfe37eb..41bbf226ef 100644 --- a/contributing/tr/syntax.texy +++ b/contributing/tr/syntax.texy @@ -1,7 +1,7 @@ Dokümantasyon sözdizimi *********************** -Dokümantasyon, bazı uzantılarla birlikte Markdown & [Texy sözdizimini |https://texy.info/cs/syntax] kullanır. +Dokümantasyon, bazı uzantılarla birlikte Markdown & [Texy sözdizimini |https://texy.nette.org/syntax] kullanır. Bağlantılar diff --git a/contributing/uk/syntax.texy b/contributing/uk/syntax.texy index de3c97be92..c9d1b66d60 100644 --- a/contributing/uk/syntax.texy +++ b/contributing/uk/syntax.texy @@ -1,7 +1,7 @@ Синтаксис документації ********************** -Документація використовує Markdown та [синтаксис Texy |https://texy.info/cs/syntax] з деякими розширеннями. +Документація використовує Markdown та [синтаксис Texy |https://texy.nette.org/syntax] з деякими розширеннями. Посилання diff --git a/database/bg/@home.texy b/database/bg/@home.texy index 3dfb819140..7eccf1677b 100644 --- a/database/bg/@home.texy +++ b/database/bg/@home.texy @@ -17,5 +17,5 @@ Nette поддържа следните бази данни: -{{title: Nette Database}} +{{maintitle: Nette Database - awesome database layer for PHP}} {{description: Nette Database значително улеснява извличането на данни от базата данни, без да е необходимо да се пишат SQL заявки. Изпълнява ефективни заявки и не прехвърля излишни данни.}} diff --git a/database/bg/@meta.texy b/database/bg/@meta.texy new file mode 100644 index 0000000000..57804a1127 --- /dev/null +++ b/database/bg/@meta.texy @@ -0,0 +1 @@ +{{sitename: Документация на Nette}} diff --git a/database/cs/@home.texy b/database/cs/@home.texy index 20cc87170b..58162d133d 100644 --- a/database/cs/@home.texy +++ b/database/cs/@home.texy @@ -17,5 +17,5 @@ Nette podporuje následující databáze: -{{title: Nette Database}} +{{maintitle: Nette Database - awesome database layer for PHP}} {{description: Nette Database zásadním způsobem zjednodušuje získávání dat z databáze bez nutnosti psát SQL dotazy. Pokládá efektivní dotazy a nepřenáší zbytečná data.}} diff --git a/database/cs/@meta.texy b/database/cs/@meta.texy new file mode 100644 index 0000000000..462d9add80 --- /dev/null +++ b/database/cs/@meta.texy @@ -0,0 +1 @@ +{{sitename: Nette Dokumentace}} diff --git a/database/cs/explorer.texy b/database/cs/explorer.texy index 24044ef827..646e033f48 100644 --- a/database/cs/explorer.texy +++ b/database/cs/explorer.texy @@ -263,7 +263,7 @@ Usnadňuje stránkování výsledků. Přijímá číslo stránky (počítané o ```php $numOfPages = null; -$table->page(page: 3, itemsPerPage: 10, $numOfPages); +$table->page(page: 3, itemsPerPage: 10, numOfPages: $numOfPages); echo "Celkem stránek: $numOfPages"; ``` diff --git a/database/de/@home.texy b/database/de/@home.texy index 90353a0fcb..45a96f08ed 100644 --- a/database/de/@home.texy +++ b/database/de/@home.texy @@ -17,5 +17,5 @@ Nette unterstützt die folgenden Datenbanken: -{{title: Nette Database}} +{{maintitle: Nette Database - awesome database layer for PHP}} {{description: Nette Database vereinfacht das Abrufen von Daten aus der Datenbank erheblich, ohne dass SQL-Abfragen geschrieben werden müssen. Es stellt effiziente Abfragen und überträgt keine unnötigen Daten.}} diff --git a/database/de/@meta.texy b/database/de/@meta.texy new file mode 100644 index 0000000000..b3b806b2ca --- /dev/null +++ b/database/de/@meta.texy @@ -0,0 +1 @@ +{{sitename: Nette Dokumentation}} diff --git a/database/el/@home.texy b/database/el/@home.texy index d97c6395c8..ff1b599908 100644 --- a/database/el/@home.texy +++ b/database/el/@home.texy @@ -17,5 +17,5 @@ -{{title: Nette Database}} +{{maintitle: Nette Database - awesome database layer for PHP}} {{description: Η Nette Database απλοποιεί σημαντικά την ανάκτηση δεδομένων από τη βάση δεδομένων χωρίς την ανάγκη γραφής ερωτημάτων SQL. Θέτει αποτελεσματικά ερωτήματα και δεν μεταφέρει περιττά δεδομένα.}} diff --git a/database/el/@meta.texy b/database/el/@meta.texy new file mode 100644 index 0000000000..88e29852c7 --- /dev/null +++ b/database/el/@meta.texy @@ -0,0 +1 @@ +{{sitename: Nette Τεκμηρίωση}} diff --git a/database/en/@home.texy b/database/en/@home.texy index 7b34e23d7a..7d7452d8d1 100644 --- a/database/en/@home.texy +++ b/database/en/@home.texy @@ -16,5 +16,5 @@ These database servers are supported: -{{title: Nette Database}} +{{maintitle: Nette Database - awesome database layer for PHP}} {{description: Nette Database significantly simplifies retrieving data from the database without writing SQL queries. It executes efficient queries and does not transfer unnecessary data.}} diff --git a/database/en/@meta.texy b/database/en/@meta.texy new file mode 100644 index 0000000000..42471908b0 --- /dev/null +++ b/database/en/@meta.texy @@ -0,0 +1 @@ +{{sitename: Nette Documentation}} diff --git a/database/en/explorer.texy b/database/en/explorer.texy index dc5e7ef7af..d08f43a51e 100644 --- a/database/en/explorer.texy +++ b/database/en/explorer.texy @@ -263,7 +263,7 @@ Facilitates pagination of results. It accepts the page number (starting from 1) ```php $numOfPages = null; -$table->page(page: 3, itemsPerPage: 10, $numOfPages); +$table->page(page: 3, itemsPerPage: 10, numOfPages: $numOfPages); echo "Total pages: $numOfPages"; ``` diff --git a/database/es/@home.texy b/database/es/@home.texy index 62e054c191..847f8e4d76 100644 --- a/database/es/@home.texy +++ b/database/es/@home.texy @@ -17,5 +17,5 @@ Nette soporta las siguientes bases de datos: -{{title: Nette Database}} +{{maintitle: Nette Database - awesome database layer for PHP}} {{description: Nette Database simplifica radicalmente la obtención de datos de la base de datos sin necesidad de escribir consultas SQL. Realiza consultas eficientes y no transfiere datos innecesarios.}} diff --git a/database/es/@meta.texy b/database/es/@meta.texy new file mode 100644 index 0000000000..1670b124ad --- /dev/null +++ b/database/es/@meta.texy @@ -0,0 +1 @@ +{{sitename: Nette Documentación}} diff --git a/database/fr/@home.texy b/database/fr/@home.texy index 672d9bd648..f05b61a24f 100644 --- a/database/fr/@home.texy +++ b/database/fr/@home.texy @@ -17,5 +17,5 @@ Nette prend en charge les bases de données suivantes : -{{title: Nette Database}} +{{maintitle: Nette Database - awesome database layer for PHP}} {{description: Nette Database simplifie considérablement l'obtention de données de la base de données sans avoir à écrire de requêtes SQL. Il exécute des requêtes efficaces et ne transfère pas de données inutiles.}} diff --git a/database/fr/@meta.texy b/database/fr/@meta.texy new file mode 100644 index 0000000000..72ae4b8db8 --- /dev/null +++ b/database/fr/@meta.texy @@ -0,0 +1 @@ +{{sitename: Documentation Nette}} diff --git a/database/hu/@home.texy b/database/hu/@home.texy index 07b7d2f61b..fc880e7b35 100644 --- a/database/hu/@home.texy +++ b/database/hu/@home.texy @@ -17,5 +17,5 @@ A Nette a következő adatbázisokat támogatja: -{{title: Nette Database}} +{{maintitle: Nette Database - awesome database layer for PHP}} {{description: A Nette Database jelentősen leegyszerűsíti az adatok lekérdezését az adatbázisból SQL lekérdezések írása nélkül. Hatékony lekérdezéseket tesz és nem továbbít felesleges adatokat.}} diff --git a/database/hu/@meta.texy b/database/hu/@meta.texy new file mode 100644 index 0000000000..c172d1cda5 --- /dev/null +++ b/database/hu/@meta.texy @@ -0,0 +1 @@ +{{sitename: Nette dokumentáció}} diff --git a/database/it/@home.texy b/database/it/@home.texy index 265f5cc820..97f1e1e9db 100644 --- a/database/it/@home.texy +++ b/database/it/@home.texy @@ -17,5 +17,5 @@ Nette supporta i seguenti database: -{{title: Nette Database}} +{{maintitle: Nette Database - awesome database layer for PHP}} {{description: Nette Database semplifica notevolmente l'ottenimento di dati dal database senza la necessità di scrivere query SQL. Esegue query efficienti e non trasferisce dati inutili.}} diff --git a/database/it/@meta.texy b/database/it/@meta.texy new file mode 100644 index 0000000000..4647d0c8a2 --- /dev/null +++ b/database/it/@meta.texy @@ -0,0 +1 @@ +{{sitename: Documentazione Nette}} diff --git a/database/ja/@home.texy b/database/ja/@home.texy index 121b7c37e7..965d3ecec8 100644 --- a/database/ja/@home.texy +++ b/database/ja/@home.texy @@ -17,5 +17,5 @@ Netteは以下のデータベースをサポートしています: -{{title: Nette Database}} +{{maintitle: Nette Database - awesome database layer for PHP}} {{description: Nette Databaseは、SQLクエリを記述する必要なく、データベースからデータを取得するプロセスを大幅に簡素化します。効率的なクエリを実行し、不要なデータを転送しません。}} diff --git a/database/ja/@meta.texy b/database/ja/@meta.texy new file mode 100644 index 0000000000..d3c41dc3d7 --- /dev/null +++ b/database/ja/@meta.texy @@ -0,0 +1 @@ +{{sitename: Nette ドキュメンテーション}} diff --git a/database/pl/@home.texy b/database/pl/@home.texy index 25f116f77f..4093fa6893 100644 --- a/database/pl/@home.texy +++ b/database/pl/@home.texy @@ -17,5 +17,5 @@ Nette obsługuje następujące bazy danych: -{{title: Nette Database}} +{{maintitle: Nette Database - awesome database layer for PHP}} {{description: Nette Database w znaczący sposób upraszcza pobieranie danych z bazy danych bez konieczności pisania zapytań SQL. Składa efektywne zapytania i nie przesyła zbędnych danych.}} diff --git a/database/pl/@meta.texy b/database/pl/@meta.texy new file mode 100644 index 0000000000..61ac92d1af --- /dev/null +++ b/database/pl/@meta.texy @@ -0,0 +1 @@ +{{sitename: Dokumentacja Nette}} diff --git a/database/pt/@home.texy b/database/pt/@home.texy index ae5a1cc937..dc4308eeae 100644 --- a/database/pt/@home.texy +++ b/database/pt/@home.texy @@ -17,5 +17,5 @@ Nette suporta os seguintes bancos de dados: -{{title: Nette Database}} +{{maintitle: Nette Database - awesome database layer for PHP}} {{description: Nette Database simplifica significativamente a obtenção de dados do banco de dados sem a necessidade de escrever consultas SQL. Ele faz consultas eficientes e não transfere dados desnecessários.}} diff --git a/database/pt/@meta.texy b/database/pt/@meta.texy new file mode 100644 index 0000000000..41a853b6aa --- /dev/null +++ b/database/pt/@meta.texy @@ -0,0 +1 @@ +{{sitename: Documentação Nette}} diff --git a/database/ro/@home.texy b/database/ro/@home.texy index 9a10cbe9b0..e6e3ddb3ab 100644 --- a/database/ro/@home.texy +++ b/database/ro/@home.texy @@ -17,5 +17,5 @@ Nette suportă următoarele baze de date: -{{title: Nette Database}} +{{maintitle: Nette Database - awesome database layer for PHP}} {{description: Nette Database simplifică semnificativ recuperarea datelor din baza de date fără a fi nevoie să scrieți interogări SQL. Execută interogări eficiente și nu transferă date inutile.}} diff --git a/database/ro/@meta.texy b/database/ro/@meta.texy new file mode 100644 index 0000000000..9c744b37d6 --- /dev/null +++ b/database/ro/@meta.texy @@ -0,0 +1 @@ +{{sitename: Documentație Nette}} diff --git a/database/ru/@home.texy b/database/ru/@home.texy index 6753a2c576..0927782214 100644 --- a/database/ru/@home.texy +++ b/database/ru/@home.texy @@ -17,5 +17,5 @@ Nette поддерживает следующие базы данных: -{{title: Nette Database}} +{{maintitle: Nette Database - awesome database layer for PHP}} {{description: Nette Database существенно упрощает получение данных из базы данных без необходимости писать SQL-запросы. Он выполняет эффективные запросы и не передает лишние данные.}} diff --git a/database/ru/@meta.texy b/database/ru/@meta.texy new file mode 100644 index 0000000000..7f329adfce --- /dev/null +++ b/database/ru/@meta.texy @@ -0,0 +1 @@ +{{sitename: Документация Nette}} diff --git a/database/sl/@home.texy b/database/sl/@home.texy index 0cca97ba14..5c0ffe069e 100644 --- a/database/sl/@home.texy +++ b/database/sl/@home.texy @@ -17,5 +17,5 @@ Nette podpira naslednje podatkovne baze: -{{title: Nette Database}} +{{maintitle: Nette Database - awesome database layer for PHP}} {{description: Nette Database bistveno poenostavlja pridobivanje podatkov iz podatkovne baze brez potrebe po pisanju SQL poizvedb. Postavlja učinkovite poizvedbe in ne prenaša nepotrebnih podatkov.}} diff --git a/database/sl/@meta.texy b/database/sl/@meta.texy new file mode 100644 index 0000000000..724324bee5 --- /dev/null +++ b/database/sl/@meta.texy @@ -0,0 +1 @@ +{{sitename: Nette Dokumentacija}} diff --git a/database/tr/@home.texy b/database/tr/@home.texy index aeb01502ee..7700df2b84 100644 --- a/database/tr/@home.texy +++ b/database/tr/@home.texy @@ -17,5 +17,5 @@ Nette aşağıdaki veritabanlarını destekler: -{{title: Nette Database}} +{{maintitle: Nette Database - awesome database layer for PHP}} {{description: Nette Database, SQL sorguları yazmaya gerek kalmadan veritabanından veri almayı önemli ölçüde basitleştirir. Etkili sorgular yapar ve gereksiz verileri aktarmaz.}} diff --git a/database/tr/@meta.texy b/database/tr/@meta.texy new file mode 100644 index 0000000000..8dfe82f311 --- /dev/null +++ b/database/tr/@meta.texy @@ -0,0 +1 @@ +{{sitename: Nette Dokümantasyonu}} diff --git a/database/uk/@home.texy b/database/uk/@home.texy index 195714c91a..9cd3b93223 100644 --- a/database/uk/@home.texy +++ b/database/uk/@home.texy @@ -17,5 +17,5 @@ Nette підтримує наступні бази даних: -{{title: Nette Database}} +{{maintitle: Nette Database - awesome database layer for PHP}} {{description: Nette Database суттєво спрощує отримання даних з бази даних без необхідності писати SQL-запити. Вона виконує ефективні запити та не передає зайвих даних.}} diff --git a/database/uk/@meta.texy b/database/uk/@meta.texy new file mode 100644 index 0000000000..96e2d9752a --- /dev/null +++ b/database/uk/@meta.texy @@ -0,0 +1 @@ +{{sitename: Документація Nette}} diff --git a/dependency-injection/bg/@meta.texy b/dependency-injection/bg/@meta.texy new file mode 100644 index 0000000000..57804a1127 --- /dev/null +++ b/dependency-injection/bg/@meta.texy @@ -0,0 +1 @@ +{{sitename: Документация на Nette}} diff --git a/dependency-injection/cs/@meta.texy b/dependency-injection/cs/@meta.texy new file mode 100644 index 0000000000..462d9add80 --- /dev/null +++ b/dependency-injection/cs/@meta.texy @@ -0,0 +1 @@ +{{sitename: Nette Dokumentace}} diff --git a/dependency-injection/cs/factory.texy b/dependency-injection/cs/factory.texy index 205b3655fd..a90573d587 100644 --- a/dependency-injection/cs/factory.texy +++ b/dependency-injection/cs/factory.texy @@ -173,7 +173,7 @@ interface MultiFactory } ``` -Takže místo toho, abych si předávali několik generovaných továren a accessorů, předáme jednu komplexnější továrnu, která toho umí víc. +Takže místo toho, abychom si předávali několik generovaných továren a accessorů, předáme jednu komplexnější továrnu, která toho umí víc. Alternativně lze místo několika metod použít `get()` s parameterem: diff --git a/dependency-injection/cs/faq.texy b/dependency-injection/cs/faq.texy index e9842c0bba..a64b806cbe 100644 --- a/dependency-injection/cs/faq.texy +++ b/dependency-injection/cs/faq.texy @@ -88,7 +88,7 @@ Mějme na paměti [Pravidlo č. 1: nech si to předat |introduction#Pravidlo č. V této ukázce je `%myParameter%` zástupný symbol pro hodnotu parametru `myParameter`, který se předá do konstruktoru třídy `MyClass`: -```php +```neon # config.neon parameters: myParameter: Some value diff --git a/dependency-injection/cs/global-state.texy b/dependency-injection/cs/global-state.texy index d152d69973..2f7ddf5caf 100644 --- a/dependency-injection/cs/global-state.texy +++ b/dependency-injection/cs/global-state.texy @@ -93,7 +93,7 @@ Musíte podrobně procházet kód, abyste zjistili, že objekt `PaymentGateway` ```php $db = new DB('mysql:', 'user', 'password'); -$gateway = new PaymentGateway($db, ...); +$gateway = new PaymentGateway($db, /* ... */); ``` Podobný problém se objevuje i při použití globálního přístupu k databázovému spojení: diff --git a/dependency-injection/cs/services.texy b/dependency-injection/cs/services.texy index 10c8e6ac30..6f4ec1bacb 100644 --- a/dependency-injection/cs/services.texy +++ b/dependency-injection/cs/services.texy @@ -181,7 +181,7 @@ public function createServiceFoo(): Foo { $service = new Foo; $service->value = 123; - $service->onClick[] = [$this->getService('bar'), 'clickHandler']; + $service->onClick[] = $this->getService('bar')->clickHandler(...); return $service; } ``` @@ -381,7 +381,7 @@ services: logger: monolog.logger.event ``` -Aby jste získali všechny služby s určitými tagy, můžete použít funkci `tagged()`: +Abyste získali všechny služby s určitými tagy, můžete použít funkci `tagged()`: ```neon services: @@ -433,8 +433,14 @@ services: application.application: create: MyApplication alteration: true - setup: - - '$onStartup[]' = [@resource, init] +``` + +Službu nemusíte identifikovat interním názvem, můžete na ni odkázat i jejím typem. Předchozí příklad tak lze zapsat i takto: + +```neon +services: + @Nette\Application\Application: + create: MyApplication ``` Při přepisování služby můžeme chtít odstranit původní argumenty, položky setup nebo tagy, k čemuž slouží `reset`: diff --git a/dependency-injection/de/@meta.texy b/dependency-injection/de/@meta.texy new file mode 100644 index 0000000000..b3b806b2ca --- /dev/null +++ b/dependency-injection/de/@meta.texy @@ -0,0 +1 @@ +{{sitename: Nette Dokumentation}} diff --git a/dependency-injection/el/@meta.texy b/dependency-injection/el/@meta.texy new file mode 100644 index 0000000000..88e29852c7 --- /dev/null +++ b/dependency-injection/el/@meta.texy @@ -0,0 +1 @@ +{{sitename: Nette Τεκμηρίωση}} diff --git a/dependency-injection/en/@meta.texy b/dependency-injection/en/@meta.texy new file mode 100644 index 0000000000..42471908b0 --- /dev/null +++ b/dependency-injection/en/@meta.texy @@ -0,0 +1 @@ +{{sitename: Nette Documentation}} diff --git a/dependency-injection/en/faq.texy b/dependency-injection/en/faq.texy index b7f65321ba..6f8b836dc9 100644 --- a/dependency-injection/en/faq.texy +++ b/dependency-injection/en/faq.texy @@ -88,7 +88,7 @@ Keep in mind [Rule #1: Let It Be Passed to You |introduction#Rule #1: Let It Be In this example, `%myParameter%` is a placeholder for the value of the `myParameter` parameter, which will be passed to the `MyClass` constructor: -```php +```neon # config.neon parameters: myParameter: Some value diff --git a/dependency-injection/en/global-state.texy b/dependency-injection/en/global-state.texy index f626392831..794f2814b3 100644 --- a/dependency-injection/en/global-state.texy +++ b/dependency-injection/en/global-state.texy @@ -93,7 +93,7 @@ You must meticulously trace the code to discover that the `PaymentGateway` objec ```php $db = new DB('mysql:', 'user', 'password'); -$gateway = new PaymentGateway($db, ...); +$gateway = new PaymentGateway($db, /* ... */); ``` A similar problem arises when using global access to a database connection: diff --git a/dependency-injection/en/services.texy b/dependency-injection/en/services.texy index 7b3ad6b364..8da30d74ed 100644 --- a/dependency-injection/en/services.texy +++ b/dependency-injection/en/services.texy @@ -181,7 +181,7 @@ public function createServiceFoo(): Foo { $service = new Foo; $service->value = 123; - $service->onClick[] = [$this->getService('bar'), 'clickHandler']; + $service->onClick[] = $this->getService('bar')->clickHandler(...); return $service; } ``` @@ -433,8 +433,14 @@ services: application.application: create: MyApplication alteration: true - setup: - - '$onStartup[]' = [@resource, init] +``` + +You don't have to identify a service by its internal name — you can refer to it by type instead. The previous example can also be written as: + +```neon +services: + @Nette\Application\Application: + create: MyApplication ``` When modifying a service, we might want to remove original arguments, setup items, or tags, using the `reset` key: diff --git a/dependency-injection/es/@meta.texy b/dependency-injection/es/@meta.texy new file mode 100644 index 0000000000..1670b124ad --- /dev/null +++ b/dependency-injection/es/@meta.texy @@ -0,0 +1 @@ +{{sitename: Nette Documentación}} diff --git a/dependency-injection/fr/@meta.texy b/dependency-injection/fr/@meta.texy new file mode 100644 index 0000000000..72ae4b8db8 --- /dev/null +++ b/dependency-injection/fr/@meta.texy @@ -0,0 +1 @@ +{{sitename: Documentation Nette}} diff --git a/dependency-injection/hu/@meta.texy b/dependency-injection/hu/@meta.texy new file mode 100644 index 0000000000..c172d1cda5 --- /dev/null +++ b/dependency-injection/hu/@meta.texy @@ -0,0 +1 @@ +{{sitename: Nette dokumentáció}} diff --git a/dependency-injection/it/@meta.texy b/dependency-injection/it/@meta.texy new file mode 100644 index 0000000000..4647d0c8a2 --- /dev/null +++ b/dependency-injection/it/@meta.texy @@ -0,0 +1 @@ +{{sitename: Documentazione Nette}} diff --git a/dependency-injection/ja/@meta.texy b/dependency-injection/ja/@meta.texy new file mode 100644 index 0000000000..d3c41dc3d7 --- /dev/null +++ b/dependency-injection/ja/@meta.texy @@ -0,0 +1 @@ +{{sitename: Nette ドキュメンテーション}} diff --git a/dependency-injection/pl/@meta.texy b/dependency-injection/pl/@meta.texy new file mode 100644 index 0000000000..61ac92d1af --- /dev/null +++ b/dependency-injection/pl/@meta.texy @@ -0,0 +1 @@ +{{sitename: Dokumentacja Nette}} diff --git a/dependency-injection/pt/@meta.texy b/dependency-injection/pt/@meta.texy new file mode 100644 index 0000000000..41a853b6aa --- /dev/null +++ b/dependency-injection/pt/@meta.texy @@ -0,0 +1 @@ +{{sitename: Documentação Nette}} diff --git a/dependency-injection/ro/@meta.texy b/dependency-injection/ro/@meta.texy new file mode 100644 index 0000000000..9c744b37d6 --- /dev/null +++ b/dependency-injection/ro/@meta.texy @@ -0,0 +1 @@ +{{sitename: Documentație Nette}} diff --git a/dependency-injection/ru/@meta.texy b/dependency-injection/ru/@meta.texy new file mode 100644 index 0000000000..7f329adfce --- /dev/null +++ b/dependency-injection/ru/@meta.texy @@ -0,0 +1 @@ +{{sitename: Документация Nette}} diff --git a/dependency-injection/sl/@meta.texy b/dependency-injection/sl/@meta.texy new file mode 100644 index 0000000000..724324bee5 --- /dev/null +++ b/dependency-injection/sl/@meta.texy @@ -0,0 +1 @@ +{{sitename: Nette Dokumentacija}} diff --git a/dependency-injection/tr/@meta.texy b/dependency-injection/tr/@meta.texy new file mode 100644 index 0000000000..8dfe82f311 --- /dev/null +++ b/dependency-injection/tr/@meta.texy @@ -0,0 +1 @@ +{{sitename: Nette Dokümantasyonu}} diff --git a/dependency-injection/uk/@meta.texy b/dependency-injection/uk/@meta.texy new file mode 100644 index 0000000000..96e2d9752a --- /dev/null +++ b/dependency-injection/uk/@meta.texy @@ -0,0 +1 @@ +{{sitename: Документація Nette}} diff --git a/dibi/cs/@home.texy b/dibi/cs/@home.texy new file mode 100644 index 0000000000..0270991509 --- /dev/null +++ b/dibi/cs/@home.texy @@ -0,0 +1,657 @@ +Dibi: Šikovná Database Abstraction Library pro PHP +************************************************** + +Nejnovější stabilní verzi Dibi instalujte pomocí [Composer|best-practices:composer] příkazem: + +``` +composer require dibi/dibi +``` + +Přehled verzí najdete na stánce [Releases | https://github.com/dg/dibi/releases]. + +Vyžaduje PHP 8.0 nebo vyšší. + + +Připojení k databázi +==================== + +Databázové spojení je reprezentováno objektem [Dibi\Connection|api:]: + +```php +$database = new Dibi\Connection([ + 'driver' => 'mysqli', + 'host' => 'localhost', + 'username' => 'root', + 'password' => '***', + 'database' => 'table', +]); + +$result = $database->query('SELECT * FROM users'); +``` + +Alternativně můžete používat statický registr `dibi`, který udržuje v globálně dostupném úložišti objekt spojení a nad ním volá všechny funkce: + +```php +dibi::connect([ + 'driver' => 'mysqli', + 'host' => 'localhost', + 'username' => 'root', + 'password' => '***', + 'database' => 'test', + 'charset' => 'utf8', +]); + +$result = dibi::query('SELECT * FROM users'); +``` + +V případě chyby připojení se vyhodí `Dibi\Exception`. + + +Dotazy +====== + +Databázové dotazy pokládáme metodou `query()`, která vrací [Dibi\Result |api:Dibi\Result]. Řádky jako objekty [Dibi\Row |api:Dibi\Row]. + +Všechny příklady si můžete zkoušet [online na hřišti |https://repl.it/@DavidGrudl/dibi-playground]. + +```php +$result = $database->query('SELECT * FROM users'); + +foreach ($result as $row) { + echo $row->id; + echo $row->name; +} + +// pole všech řádků +$all = $result->fetchAll(); + +// pole všech řádků, klíčem je 'id' +$all = $result->fetchAssoc('id'); + +// asociativní pole id => name +$pairs = $result->fetchPairs('id', 'name'); + +// počet řádků výsledku, pokud je znám, nebo počet ovlivněných řádků +$count = $result->getRowCount(); +``` + +Metoda fetchAssoc() umí vracet i [složitější asociativní pole |#Výsledek jako asociativní pole]. + +Do dotazu lze velmi snadno přidávat i parametry, všimněte si otazníku: + +```php +$result = $database->query('SELECT * FROM users WHERE name = ? AND active = ?', $name, $active); + +// nebo +$result = $database->query('SELECT * FROM users WHERE name = ?', $name, 'AND active = ?', $active); + +$ids = [10, 20, 30]; +$result = $database->query('SELECT * FROM users WHERE id IN (?)', $ids); +``` + +
+**POZOR, nikdy dotazy neskládejte jako řetězce, vznikla by zranitelnost [SQL injection |https://cs.wikipedia.org/wiki/SQL_injection]** +/-- +$database->query('SELECT * FROM users WHERE id = ' . $id); // ŠPATNĚ!!! +\-- +
+ +Místo otazníku lze používat i tzv. [#modifikátory]. + +```php +$result = $database->query('SELECT * FROM users WHERE name = %s', $name); +``` + +V případě selhání `query()` vyhodí buď `Dibi\Exception`, nebo některého z potomků: + +- [ConstraintViolationException |api:Dibi\ConstraintViolationException] - porušení nějakého omezení pro tabulku +- [ForeignKeyConstraintViolationException |api:Dibi\ForeignKeyConstraintViolationException] - neplatný cizí klíč +- [NotNullConstraintViolationException |api:Dibi\NotNullConstraintViolationException] - porušení podmínky NOT NULL +- [UniqueConstraintViolationException |api:Dibi\UniqueConstraintViolationException] - koliduje unikátní index + +Dotazy lze pokládat také pomocí zkratek: + +```php +// vrátí asociativní pole id => name, zkratka pro query(...)->fetchPairs() +$pairs = $database->fetchPairs('SELECT id, name FROM users'); + +// vrátí pole všech řádků, zkratka pro query(...)->fetchAll() +$rows = $database->fetchAll('SELECT * FROM users'); + +// vrátí řádek, zkratka pro query(...)->fetch() +$row = $database->fetch('SELECT * FROM users WHERE id = ?', $id); + +// vrátí buňku, zkratka pro query(...)->fetchSingle() +$name = $database->fetchSingle('SELECT name FROM users WHERE id = ?', $id); +``` + + +Modifikátory +============ + +Kromě zástupného symbolu `?` můžeme používat i modifikátory: + +| %s | string +| %sN | string, ale '' se přeloží jako NULL +| %bin | binární data +| %b | boolean +| %i | integer +| %iN | integer, ale 0 se přeloží jako NULL +| %f | float +| %d | datum (očekává DateTime, string nebo UNIX timestamp) +| %dt | datum & čas (očekává DateTime, string nebo UNIX timestamp) +| %n | identifikátor, tedy název tabulky či sloupce +| %N | identifikátor, považuje tečku za běžný znak +| %SQL | SQL - přímo vloží do SQL (alternativou je Dibi\Literal) +| %ex | expanduje pole +| %lmt | speciální - doplní do dotazu LIMIT +| %ofs | speciální - doplní do dotazu OFFSET + +Příklad: + +```php +$result = $database->query('SELECT * FROM users WHERE name = %s', $name); +``` + +Pokud `$name` je `null`, vloží se do SQL příkazu `NULL`. + +Pokud proměnná je pole, tak se modifikátor aplikuje na všechny jeho prvky a ty se vloží do SQL oddělené čárkami: + +```php +$ids = [10, '20', 30]; +$result = $database->query('SELECT * FROM users WHERE id IN (%i)', $ids); +// SELECT * FROM users WHERE id IN (10, 20, 30) +``` + +Modifikátor `%n` využijete v případě, že název tabulky nebo sloupce je proměnnou. (Pozor, nedovolte uživateli manipulovat s obsahem takové proměnné): + +```php +$table = 'blog.users'; +$column = 'name'; +$result = $database->query('SELECT * FROM %n WHERE %n = ?', $table, $column, $value); +// SELECT * FROM `blog`.`users` WHERE `name` = 'Jim' +``` + +Pro operátor LIKE jsou k dispozici čtyři speciální modifikátory: + +| %like~ | výraz začíná řetězcem +| %~like | výraz končí řetězcem +| %~like~ | výraz obsahuje řetězec +| `%like` | výraz je řetězec + +Hledej jména začínající na určitý řetězec: + +```php +$result = $database->query('SELECT * FROM table WHERE name LIKE %like~', $query); +``` + + +Modifikátory polí +================= + +Parameterem vkládaným do SQL dotazu může být i pole. Tyto modifikátory určují, jak z něj sestavit SQL příkaz: + +| %and | | `key1 = value1 AND key2 = value2 AND ...` +| %or | | `key1 = value1 OR key2 = value2 OR ...` +| %a | assoc | `key1 = value1, key2 = value2, ...` +| %l %in | list | `(val1, val2, ...)` +| %v | values | `(key1, key2, ...) VALUES (value1, value2, ...)` +| %m | multi | `(key1, key2, ...) VALUES (value1, value2, ...), (value1, value2, ...), ...` +| %by | řazení | `key1 ASC, key2 DESC ...` +| %n | názvy | `key1, key2 AS alias, ...` + +Příklad: + +```php +$arr = [ + 'a' => 'hello', + 'b' => true, +]; + +$database->query('INSERT INTO table %v', $arr); +// INSERT INTO `table` (`a`, `b`) VALUES ('hello', 1) + +$database->query('UPDATE `table` SET %a', $arr); +// UPDATE `table` SET `a`='hello', `b`=1 +``` + +V klauzuli WHERE lze použít modifikátory `%and` nebo `%or`: + +```php +$result = $database->query('SELECT * FROM users WHERE %and', [ + 'name' => $name, + 'year' => $year, +]); +// SELECT * FROM users WHERE `name` = 'Jim' AND `year` = 1978 +``` + +Viz také [#Složitější dotazy]. + +Modifikátor `%by` slouží k řazení, v klíčích uvedeme sloupce a hodnotou bude boolean určující, zda řadit vzestupně: + +```php +$result = $database->query('SELECT id FROM author ORDER BY %by', [ + 'id' => true, // vzestupně + 'name' => false, // sestupně +]); +// SELECT id FROM author ORDER BY `id`, `name` DESC +``` + + +Insert, Update & Delete +======================= + +Data vkládáme do SQL dotazu jako asociativní pole. Modifikátory ani zástupný znak `?` není nutné v těchto případech uvádět. + +```php +$database->query('INSERT INTO users', [ + 'name' => $name, + 'year' => $year, +]); +// INSERT INTO users (`name`, `year`) VALUES ('Jim', 1978) + +$id = $database->getInsertId(); // vrátí auto-increment vloženého záznamu + +$id = $database->getInsertId($sequence); // nebo hodnotu sekvence +``` + +Vícenásobný INSERT: + +```php +$database->query( + 'INSERT INTO users', + [ + 'name' => 'Jim', + 'year' => 1978, + ], + [ + 'name' => 'Jack', + 'year' => 1987, + ] +); +// INSERT INTO users (`name`, `year`) VALUES ('Jim', 1978), ('Jack', 1987) +``` + +Mazání: + +```php +$database->query('DELETE FROM users WHERE id = ?', $id); + +// vrací počet smazaných řádků +$affectedRows = $database->getAffectedRows(); +``` + +Úprava záznamů: + +```php +$database->query('UPDATE users SET', [ + 'name' => $name, + 'year' => $year, +], 'WHERE id = ?', $id); +// UPDATE users SET `name` = 'Jim', `year` = 1978 WHERE id = 123 + +// vrací počet změněných řádků +$affectedRows = $database->getAffectedRows(); +``` + +Vložení záznamu, nebo úprava, pokud již existuje: + +```php +$database->query('INSERT INTO users', [ + 'id' => $id, + 'name' => $name, + 'year' => $year, +], 'ON DUPLICATE KEY UPDATE %a', [ // tady už modifikátor %a uvést musíme + 'name' => $name, + 'year' => $year, +]); +// INSERT INTO users (`id`, `name`, `year`) VALUES (123, 'Jim', 1978) +// ON DUPLICATE KEY UPDATE `name` = 'Jim', `year` = 1978 +``` + + +Transakce +========= + +Pro práci s transakcemi slouží čtveřice metod: + +```php +$database->beginTransaction(); // zahájení transakce + +$database->commit(); // potvrzení + +$database->rollback(); // vrácení zpět + +$database->transaction(function () { + // nejaka akce +}); +``` + + +Testování +========= + +Abyste si mohli trošku s Dibi hrát, je tu připravena metoda `test()`, které předáte parametry stejně jako `query()`, ovšem místo provedení SQL příkazu se tento barevně vypíše na obrazovku. + +Výsledky dotazu je možné vypsat jako tabulku pomocí `$result->dump()`. + +K dispozici jsou dále proměnné: + +```php +dibi::$sql; // poslední SQL příklaz +dibi::$elapsedTime; // jeho doba trvání v sec +dibi::$numOfQueries; // celkem SQL příkazů +dibi::$totalTime; // celkový čas v sec +``` + + +Složitější dotazy +================= + +Parametrem může být také objekt `DateTime`. + +```php +$result = $database->query('SELECT * FROM users WHERE created < ?', new DateTime); + +$database->query('INSERT INTO users', [ + 'created' => new DateTime, +]); +``` + +Nebo SQL literál: + +```php +$database->query('UPDATE table SET', [ + 'date' => $database->literal('NOW()'), +]); +// UPDATE table SET `date` = NOW() +``` + +Nebo výraz, ve kterém lze používat zástupné znaky `?` nebo modifikátory: + +```php +$database->query('UPDATE `table` SET', [ + 'title' => $database::expression('SHA1(?)', 'tajne'), +]); +// UPDATE `table` SET `title` = SHA1('tajne') +``` + +Při update lze modifikátory uvádět přímo v klíčích: + +```php +$database->query('UPDATE table SET', [ + 'date%SQL' => 'NOW()', // %SQL znamená SQL ;) +]); +// UPDATE table SET `date` = NOW() +``` + +V podmínkách (tj. u modifikátorů `%and` a `%or`) není nutné uvádět klíče: + +```php +$result = $database->query('SELECT * FROM `table` WHERE %and', [ + 'number > 10', + 'number < 100', +]); +// SELECT * FROM `table` WHERE (number > 10) AND (number < 100) +``` + +V položkách lze používat i modifikátory nebo zástupné znaky: + +```php +$result = $database->query('SELECT * FROM `table` WHERE %and', [ + ['number > ?', 10], // nebo $database::expression('number > ?', 10) + ['number < ?', 100], + ['%or', [ + 'left' => 1, + 'top' => 2, + ]], +]); +// SELECT * FROM `table` WHERE (number > 10) AND (number < 100) AND (`left` = 1 OR `top` = 2) +``` + +Modifikátor `%ex` vloží do SQL všechny prvky pole: + +```php +$result = $database->query('SELECT * FROM `table` WHERE %ex', [ + $database::expression('left = ?', 1), + 'AND', + 'top IS NULL', +]); +// SELECT * FROM `table` WHERE left = 1 AND top IS NULL +``` + + +Podmínky v SQL příkazu +====================== + +Podmíněné SQL příkazy se ovládají pomocí tří modifikátorů `%if`, `%else` a `%end`. První z nich `%if` se musí nacházet zcela na konci řetězce představujícího SQL a za ním následuje proměnná: + +```php +//$user = ???; + +$result = $database->query(' + SELECT * + FROM table + %if', isset($user), 'WHERE user=%s', $user, '%end + ORDER BY name +'); +``` + +Podmínku lze doplnit o část `%else`: + +```php +$result = $database->query(' + SELECT * + FROM %if', $cond, 'one_table %else second_table +'); +``` + +Podmínky můžete zanořovat do sebe. + + +Identifikátory a řetězce v SQL +============================== + +Samotné SQL prochází zpracováním, aby vyhovovalo konvencím dané databáze. Identifikátory (jména tabulek a sloupců) lze uvozovat do hranatých závorek nebo zpětných uvozovek, dále řetězce jednoduchými či dvojitými uvozovkami, nicméně na server se pošle vždy to, co databáze žádá. Příklad + +```php +$database->query("UPDATE `table` SET [status]='I''m fine'"); +// MySQL: UPDATE `table` SET `status`='I\'m fine' +// ODBC: UPDATE [table] SET [status]='I''m fine' +``` + +Uvozovka se uvnitř řetězce v SQL zapisuje zdvojením. + + +Výsledek jako asociativní pole +============================== + +Příklad: vrátí výsledky jako asociativního pole, kde klíčem bude hodnota políčka `id`: + +```php +$assoc = $result->fetchAssoc('id'); +``` + +Největší síla funkce `fetchAssoc()` se projeví u SQL dotazu spojujícího několik tabulek s různými typy vazeb. Databáze z toho udělá plochou tabulku, fetchAssoc jí vrátí tvar. + +Příklad: Mějme tabulku zákazníků a objednávek (vazba N:M) a položíme dotaz: + +```php +$result = $database->query(' + SELECT customer_id, customers.name, order_id, orders.number, ... + FROM customers + INNER JOIN orders USING (customer_id) + WHERE ... +'); +``` + +A rádi bychom získali vnořené asociativní pole podle ID zákazníka a poté podle ID objednávky: + +```php +$all = $result->fetchAssoc('customer_id|order_id'); + +// budeme jej procházet takto: +foreach ($all as $customerId => $orders) { + foreach ($orders as $orderId => $order) { + // ... + } +} +``` + +Asociativní deskriptor má obdobnou syntax, jako když pole píšete pomocí přiřazení v PHP. Tedy `'customer_id|order_id'` představuje sérii přiřazení `$all[$customerId][$orderId] = $row;`, postupně pro všechny řádky. + +Někdy by se hodilo, aby se asociovalo podle jména zákazníka namísto jeho ID: + +```php +$all = $result->fetchAssoc('name|order_id'); + +// k prvkům pak přistupujeme třeba takto: +$order = $all['Arnold Rimmer'][$orderId]; +``` + +Co když ale existuje více zákazníků se stejným jménem? Tabulka by měla mít spíš tvar: + +```php +$row = $all['Arnold Rimmer'][0][$orderId]; +$row = $all['Arnold Rimmer'][1][$orderId]; +``` + +Rozlišujeme tedy více možných Rimmerů pomocí klasického pole. Asociativní deskriptor má opět formát podobný přiřazování, s tím, že sekvenční pole představuje `[]`: + +```php +$all = $result->fetchAssoc('name[]order_id'); + +// iterujeme všechny Arnoldy ve výsledcích +foreach ($all['Arnold Rimmer'] as $arnoldOrders) { + foreach ($arnoldOrders as $orderId => $order) { + // ... + } +} +``` + +Vrátíme se k příkladu s deskriptorem `'customer_id|order_id'` a zkusíme vypsat objednávky jednotlivých zákazníků: + +```php +$all = $result->fetchAssoc('customer_id|order_id'); + +foreach ($all as $customerId => $orders) { + echo "Objednávky zákazníka $customerId:"; + + foreach ($orders as $orderId => $order) { + echo "Číslo dokladu: $order->number"; + // jméno zákazníka je v $order->name + } +} +``` + +Bylo by hezké místo ID zákazníka vypsat jeho jméno. Jenže to bychom museli dohledávat v poli `$orders`. Výsledky si proto necháme upravit do takovéhoto tvaru: + +```php +$all[$customerId]->name = 'John Doe'; +$all[$customerId]->order_id[$orderId] = $row; +$all[$customerId]->order_id[$orderId2] = $row2; +``` + +Tedy mezi `$customerId` a `$orderId` vložíme ještě mezičlánek. Tentokrát ne číslované indexy, jaké jsme použili pro odlišení jednotlivých Rimmerů, ale rovnou databázový záznam. Řešení je velmi podobné, jen si stačí zapamatovat, že záznam symbolizuje šipka: + +```php +$all = $result->fetchAssoc('customer_id->order_id'); + +foreach ($all as $customerId => $row) { + echo "Objednávky zákazníka $row->name:"; + + foreach ($row->order_id as $orderId => $order) { + echo "Číslo dokladu: $order->number"; + } +} +``` + + +Prefixy & substituce +==================== + +Názvy tabulek a sloupců mohou obsahovat proměnné části. Ty si nejprve nadefinujeme: + +```php +// vytvoří novou substituci :blog: ==> wp_ +$database->substitute('blog', 'wp_'); +``` + +a poté použijeme v SQL. Všimněte si, že v SQL jsou uvozeny dvojtečkama: + +```php +$database->query("UPDATE [:blog:items] SET [text]='Hello World'"); +// UPDATE `wp_items` SET `text`='Hello World' +``` + + +Datové typy buňek +================= + +Dibi automaticky detekuje typy jednotlivých sloupců dotazu a převádí buňky na nativní typy PHP. Typ můžeme určit i manuálně. Možné typy najdete ve třídě [Dibi\Type |api:Dibi\Type]. + +```php +$result->setType('id', Dibi\Type::INTEGER); // id bude integer +$row = $result->fetch(); + +is_int($row->id) // true +``` + + +Logování +======== + +Dibi má v sobě zabudovaný logger, kterým můžete sledovat všechny vykonané SQL příkazy a měřit délku jejich trvání. Aktivace: + +```php +$database->connect([ + 'driver' => 'sqlite', + 'database' => 'sample.sdb', + 'profiler' => [ + 'file' => 'file.log', + ], +]); +``` + +Šikovnější profiler je panel pro Tracy, který se aktivuje při propojení s Nette. + + +Připojení do [Nette |https://nette.org] +======================================= + +V konfiguračním souboru zaregistrujeme DI rozšíření a přidáme sekci `dibi` - tím se vytvoří potřebné objekty a také databázový panel v [Tracy |https://tracy.nette.org] debugger baru. + +```neon +extensions: + dibi: Dibi\Bridges\Nette\DibiExtension22 + +dibi: + host: localhost + username: root + password: *** + database: foo + lazy: true +``` + +Poté objekt spojení [získáme jako službu z DI kontejneru |https://doc.nette.org/di-usage], např.: + +```php +class Model +{ + private $database; + + public function __construct(Dibi\Connection $database) + { + $this->database = $database; + } +} +``` + + +Komunitní rozšíření +=================== + +Nad Dibi staví nejrůznější knihovny, ORM a rozšíření. Celý jejich seznam najdete na "Packagistu":https://packagist.org/packages/dibi/dibi/dependents?order_by=downloads&requires=require. + + +{{maintitle: Dibi – Šikovná Database Abstraction Library pro PHP}} diff --git a/dibi/cs/@menu.texy b/dibi/cs/@menu.texy new file mode 100644 index 0000000000..271662aad7 --- /dev/null +++ b/dibi/cs/@menu.texy @@ -0,0 +1,4 @@ +- [Úvod | @home] +- "Blog .[link-external]":https://phpfashion.com/category/dibi +- "API .[link-external]":https://api.nette.org/dibi/ +- "GitHub .[link-external]":https://github.com/dg/dibi diff --git a/dibi/cs/@meta.texy b/dibi/cs/@meta.texy new file mode 100644 index 0000000000..49d44d0cfa --- /dev/null +++ b/dibi/cs/@meta.texy @@ -0,0 +1 @@ +{{sitename: Dibi Dokumentace}} diff --git a/dibi/en/@home.texy b/dibi/en/@home.texy new file mode 100644 index 0000000000..a227c5627e --- /dev/null +++ b/dibi/en/@home.texy @@ -0,0 +1,656 @@ +Dibi: Smart Database Abstraction Library for PHP +************************************************ + +To install the latest stable Dibi version, use the [Composer|best-practices:composer] command: + +``` +composer require dibi/dibi +``` + +You can find version overview on the [Releases | https://github.com/dg/dibi/releases] page. + +Requires PHP 8.0 or newer. + + +Connecting to Database +====================== + +The database connection is represented by the [Dibi\Connection|api:] object: + +```php +$database = new Dibi\Connection([ + 'driver' => 'mysqli', + 'host' => 'localhost', + 'username' => 'root', + 'password' => '***', + 'database' => 'table', +]); + +$result = $database->query('SELECT * FROM users'); +``` + +Alternatively, you can use the `dibi` static registry, which maintains a connection object in globally accessible storage and calls all functions on it: + +```php +dibi::connect([ + 'driver' => 'mysqli', + 'host' => 'localhost', + 'username' => 'root', + 'password' => '***', + 'database' => 'test', + 'charset' => 'utf8', +]); + +$result = dibi::query('SELECT * FROM users'); +``` + +In case of a connection error, it throws `Dibi\Exception`. + + +Queries +======= + +We query the database using the `query()` method, which returns [Dibi\Result |api:Dibi\Result]. Rows are returned as [Dibi\Row |api:Dibi\Row] objects. + +You can try all the examples [online at the playground |https://repl.it/@DavidGrudl/dibi-playground]. + +```php +$result = $database->query('SELECT * FROM users'); + +foreach ($result as $row) { + echo $row->id; + echo $row->name; +} + +// array of all rows +$all = $result->fetchAll(); + +// array of all rows, keyed by 'id' +$all = $result->fetchAssoc('id'); + +// associative pairs id => name +$pairs = $result->fetchPairs('id', 'name'); + +// number of result rows, if known, or number of affected rows +$count = $result->getRowCount(); +``` + +The fetchAssoc() method can return [more complex associative arrays |#Result as associative array]. + +You can easily add parameters to the query - note the question mark: + +```php +$result = $database->query('SELECT * FROM users WHERE name = ? AND active = ?', $name, $active); + +// or +$result = $database->query('SELECT * FROM users WHERE name = ?', $name, 'AND active = ?', $active); + +$ids = [10, 20, 30]; +$result = $database->query('SELECT * FROM users WHERE id IN (?)', $ids); +``` + +
+**WARNING: never concatenate parameters into SQL queries, as this would create [SQL injection |https://en.wikipedia.org/wiki/SQL_injection] vulnerability** +/-- +$database->query('SELECT * FROM users WHERE id = ' . $id); // BAD!!! +\-- +
+ +Instead of question marks, you can also use so-called [#modifiers]. + +```php +$result = $database->query('SELECT * FROM users WHERE name = %s', $name); +``` + +In case of failure, `query()` throws either `Dibi\Exception` or one of its descendants: + +- [ConstraintViolationException |api:Dibi\ConstraintViolationException] - violation of some table constraint +- [ForeignKeyConstraintViolationException |api:Dibi\ForeignKeyConstraintViolationException] - invalid foreign key +- [NotNullConstraintViolationException |api:Dibi\NotNullConstraintViolationException] - violation of the NOT NULL condition +- [UniqueConstraintViolationException |api:Dibi\UniqueConstraintViolationException] - collision with unique index + +You can also use shortcut methods: + +```php +// returns associative pairs id => name, shortcut for query(...)->fetchPairs() +$pairs = $database->fetchPairs('SELECT id, name FROM users'); + +// returns array of all rows, shortcut for query(...)->fetchAll() +$rows = $database->fetchAll('SELECT * FROM users'); + +// returns row, shortcut for query(...)->fetch() +$row = $database->fetch('SELECT * FROM users WHERE id = ?', $id); + +// returns cell, shortcut for query(...)->fetchSingle() +$name = $database->fetchSingle('SELECT name FROM users WHERE id = ?', $id); +``` + + +Modifiers +========= + +In addition to the `?` placeholder, we can also use modifiers: + +| %s | string +| %sN | string, but '' translates as NULL +| %bin | binary data +| %b | boolean +| %i | integer +| %iN | integer, but 0 translates as NULL +| %f | float +| %d | date (accepts DateTime, string or UNIX timestamp) +| %dt | datetime (accepts DateTime, string or UNIX timestamp) +| %n | identifier, i.e. table or column name +| %N | identifier, treats period as ordinary character +| %SQL | SQL - directly inserts into SQL (alternative is Dibi\Literal) +| %ex | expands array +| %lmt | special - adds LIMIT to the query +| %ofs | special - adds OFFSET to the query + +Example: + +```php +$result = $database->query('SELECT * FROM users WHERE name = %s', $name); +``` + +If `$name` is `null`, `NULL` is inserted into the SQL statement. + +If the variable is an array, the modifier is applied to all of its elements and they are inserted into SQL separated by commas: + +```php +$ids = [10, '20', 30]; +$result = $database->query('SELECT * FROM users WHERE id IN (%i)', $ids); +// SELECT * FROM users WHERE id IN (10, 20, 30) +``` + +The `%n` modifier is used when the table or column name is a variable. (Beware: do not allow the user to manipulate the content of such a variable): + +```php +$table = 'blog.users'; +$column = 'name'; +$result = $database->query('SELECT * FROM %n WHERE %n = ?', $table, $column, $value); +// SELECT * FROM `blog`.`users` WHERE `name` = 'Jim' +``` + +Four special modifiers are available for the LIKE operator: + +| %like~ | expression starts with string +| %~like | expression ends with string +| %~like~ | expression contains string +| `%like` | expression matches string + +Search for names starting with a certain string: + +```php +$result = $database->query('SELECT * FROM table WHERE name LIKE %like~', $query); +``` + + +Array Modifiers +=============== + +The parameter inserted into an SQL query can also be an array. These modifiers determine how to construct the SQL statement from it: + +| %and | | `key1 = value1 AND key2 = value2 AND ...` +| %or | | `key1 = value1 OR key2 = value2 OR ...` +| %a | assoc | `key1 = value1, key2 = value2, ...` +| %l %in | list | `(val1, val2, ...)` +| %v | values | `(key1, key2, ...) VALUES (value1, value2, ...)` +| %m | multi | `(key1, key2, ...) VALUES (value1, value2, ...), (value1, value2, ...), ...` +| %by | ordering | `key1 ASC, key2 DESC ...` +| %n | names | `key1, key2 AS alias, ...` + +Example: + +```php +$arr = [ + 'a' => 'hello', + 'b' => true, +]; + +$database->query('INSERT INTO table %v', $arr); +// INSERT INTO `table` (`a`, `b`) VALUES ('hello', 1) + +$database->query('UPDATE `table` SET %a', $arr); +// UPDATE `table` SET `a`='hello', `b`=1 +``` + +In the WHERE clause, you can use `%and` or `%or` modifiers: + +```php +$result = $database->query('SELECT * FROM users WHERE %and', [ + 'name' => $name, + 'year' => $year, +]); +// SELECT * FROM users WHERE `name` = 'Jim' AND `year` = 1978 +``` + +See also [#Complex queries]. + +The `%by` modifier is used for sorting - keys specify the columns, and the boolean value determines whether to sort in ascending order: + +```php +$result = $database->query('SELECT id FROM author ORDER BY %by', [ + 'id' => true, // ascending + 'name' => false, // descending +]); +// SELECT id FROM author ORDER BY `id`, `name` DESC +``` + + +Insert, Update & Delete +======================= + +We insert data into SQL queries as associative arrays. Modifiers and the `?` placeholder are not necessary in these cases. + +```php +$database->query('INSERT INTO users', [ + 'name' => $name, + 'year' => $year, +]); +// INSERT INTO users (`name`, `year`) VALUES ('Jim', 1978) + +$id = $database->getInsertId(); // returns the auto-increment of the inserted record + +$id = $database->getInsertId($sequence); // or sequence value +``` + +Multiple INSERT: + +```php +$database->query( + 'INSERT INTO users', + [ + 'name' => 'Jim', + 'year' => 1978, + ], + [ + 'name' => 'Jack', + 'year' => 1987, + ] +); +// INSERT INTO users (`name`, `year`) VALUES ('Jim', 1978), ('Jack', 1987) +``` + +Deleting: + +```php +$database->query('DELETE FROM users WHERE id = ?', $id); + +// returns number of deleted rows +$affectedRows = $database->getAffectedRows(); +``` + +Updating records: + +```php +$database->query('UPDATE users SET', [ + 'name' => $name, + 'year' => $year, +], 'WHERE id = ?', $id); +// UPDATE users SET `name` = 'Jim', `year` = 1978 WHERE id = 123 + +// returns the number of updated rows +$affectedRows = $database->getAffectedRows(); +``` + +Substitute any identifier: + +```php +$database->query('INSERT INTO users', [ + 'id' => $id, + 'name' => $name, + 'year' => $year, +], 'ON DUPLICATE KEY UPDATE %a', [ // here the modifier %a must be used + 'name' => $name, + 'year' => $year, +]); +// INSERT INTO users (`id`, `name`, `year`) VALUES (123, 'Jim', 1978) +// ON DUPLICATE KEY UPDATE `name` = 'Jim', `year` = 1978 +``` + + +Transaction +=========== + +There are four methods for dealing with transactions: + +```php +$database->beginTransaction(); + +$database->commit(); + +$database->rollback(); + +$database->transaction(function () { + // some action +}); +``` + + +Testing +======= + +In order to play with Dibi a little, there is a `test()` method that you pass parameters like to `query()`, but instead of executing the SQL statement, it is echoed on the screen. + +The query results can be echoed as a table using `$result->dump()`. + +These variables are also available: + +```php +dibi::$sql; // the latest SQL query +dibi::$elapsedTime; // its duration in sec +dibi::$numOfQueries; +dibi::$totalTime; +``` + + +Complex Queries +=============== + +The parameter may also be an object `DateTime`. + +```php +$result = $database->query('SELECT * FROM users WHERE created < ?', new DateTime); + +$database->query('INSERT INTO users', [ + 'created' => new DateTime, +]); +``` + +Or SQL literal: + +```php +$database->query('UPDATE table SET', [ + 'date' => $database->literal('NOW()'), +]); +// UPDATE table SET `date` = NOW() +``` + +Or an expression in which you can use `?` or modifiers: + +```php +$database->query('UPDATE `table` SET', [ + 'title' => $database::expression('SHA1(?)', 'secret'), +]); +// UPDATE `table` SET `title` = SHA1('secret') +``` + +When updating, modifiers can be placed directly in the keys: + +```php +$database->query('UPDATE table SET', [ + 'date%SQL' => 'NOW()', // %SQL means SQL ;) +]); +// UPDATE table SET `date` = NOW() +``` + +In conditions (ie, for `%and` and `%or` modifiers), it is not necessary to specify the keys: + +```php +$result = $database->query('SELECT * FROM `table` WHERE %and', [ + 'number > 10', + 'number < 100', +]); +// SELECT * FROM `table` WHERE (number > 10) AND (number < 100) +``` + +Modifiers or placeholders can also be used in expressions: + +```php +$result = $database->query('SELECT * FROM `table` WHERE %and', [ + ['number > ?', 10], // or $database::expression('number > ?', 10) + ['number < ?', 100], + ['%or', [ + 'left' => 1, + 'top' => 2, + ]], +]); +// SELECT * FROM `table` WHERE (number > 10) AND (number < 100) AND (`left` = 1 OR `top` = 2) +``` + +The `%ex` modifier inserts all items of the array into SQL: + +```php +$result = $database->query('SELECT * FROM `table` WHERE %ex', [ + $database::expression('left = ?', 1), + 'AND', + 'top IS NULL', +]); +// SELECT * FROM `table` WHERE left = 1 AND top IS NULL +``` + + +Conditions in SQL Statements +============================ + +Conditional SQL statements are controlled by three modifiers: `%if`, `%else`, and `%end`. The `%if` must be at the end of the string representing SQL and is followed by a variable: + +```php +//$user = ???; + +$result = $database->query(' + SELECT * + FROM table + %if', isset($user), 'WHERE user=%s', $user, '%end + ORDER BY name +'); +``` + +The condition can be supplemented with an `%else` section: + +```php +$result = $database->query(' + SELECT * + FROM %if', $cond, 'one_table %else second_table +'); +``` + +Conditions can be nested within each other. + + +Identifiers and Strings in SQL +============================== + +SQL itself goes through processing to meet the conventions of the given database. Identifiers (table and column names) can be enclosed in square brackets or backticks, and strings in single or double quotes, but the server always sends what the database requires. Example: + +```php +$database->query("UPDATE `table` SET [status]='I''m fine'"); +// MySQL: UPDATE `table` SET `status`='I\'m fine' +// ODBC: UPDATE [table] SET [status]='I''m fine' +``` + +Quotes inside strings in SQL are written by doubling them. + + +Result as Associative Array +=========================== + +Example: returns results as an associative array where the key will be the value of the `id` field: + +```php +$assoc = $result->fetchAssoc('id'); +``` + +The greatest power of `fetchAssoc()` is demonstrated in SQL queries joining several tables with different types of relationships. The database creates a flat table, fetchAssoc restores the shape. + +Example: Let's have a customer and order table (N:M relationship) and query: + +```php +$result = $database->query(' + SELECT customer_id, customers.name, order_id, orders.number, ... + FROM customers + INNER JOIN orders USING (customer_id) + WHERE ... +'); +``` + +And we'd like to get a nested associative array by Customer ID and then by Order ID: + +```php +$all = $result->fetchAssoc('customer_id|order_id'); + +// we will iterate like this: +foreach ($all as $customerId => $orders) { + foreach ($orders as $orderId => $order) { + // ... + } +} +``` + +The associative descriptor has similar syntax to when you write arrays using assignment in PHP. Thus `'customer_id|order_id'` represents the assignment series `$all[$customerId][$orderId] = $row;` sequentially for all rows. + +Sometimes it would be useful to associate by the customer's name instead of their ID: + +```php +$all = $result->fetchAssoc('name|order_id'); + +// elements are then accessed like this: +$order = $all['Arnold Rimmer'][$orderId]; +``` + +But what if there are multiple customers with the same name? The table should have the form: + +```php +$row = $all['Arnold Rimmer'][0][$orderId]; +$row = $all['Arnold Rimmer'][1][$orderId]; +``` + +So we distinguish multiple possible Rimmers using a regular array. The associative descriptor again has a format similar to assignment, with sequential arrays represented by `[]`: + +```php +$all = $result->fetchAssoc('name[]order_id'); + +// we iterate all Arnolds in the results +foreach ($all['Arnold Rimmer'] as $arnoldOrders) { + foreach ($arnoldOrders as $orderId => $order) { + // ... + } +} +``` + +Returning to the example with the `customer_id|order_id` descriptor, let's try to list orders for each customer: + +```php +$all = $result->fetchAssoc('customer_id|order_id'); + +foreach ($all as $customerId => $orders) { + echo "Orders for customer $customerId:"; + + foreach ($orders as $orderId => $order) { + echo "Document number: $order->number"; + // customer name is in $order->name + } +} +``` + +It would be nice to display the customer name instead of ID. But we would have to look it up in the `$orders` array. So let's modify the results to have this shape: + +```php +$all[$customerId]->name = 'John Doe'; +$all[$customerId]->order_id[$orderId] = $row; +$all[$customerId]->order_id[$orderId2] = $row2; +``` + +So, between `$customerId` and `$orderId`, we insert an intermediate element. This time not numbered indexes as we used to distinguish individual Rimmers, but directly a database record. The solution is very similar - just remember that a record is symbolized by an arrow: + +```php +$all = $result->fetchAssoc('customer_id->order_id'); + +foreach ($all as $customerId => $row) { + echo "Orders for customer $row->name:"; + + foreach ($row->order_id as $orderId => $order) { + echo "Document number: $order->number"; + } +} +``` + + +Prefixes & Substitutions +======================== + +Table and column names can contain variable parts. You will first define them: + +```php +// create new substitution :blog: ==> wp_ +$database->substitute('blog', 'wp_'); +``` + +and then use them in SQL. Note that in SQL they are enclosed in colons: + +```php +$database->query("UPDATE [:blog:items] SET [text]='Hello World'"); +// UPDATE `wp_items` SET `text`='Hello World' +``` + + +Field Data Types +================ + +Dibi automatically detects the types of individual query columns and converts cells to native PHP types. We can also specify the type manually. Possible types can be found in the [Dibi\Type |api:Dibi\Type] class. + +```php +$result->setType('id', Dibi\Type::INTEGER); // id will be integer +$row = $result->fetch(); + +is_int($row->id) // true +``` + + +Logging +======= + +Dibi has a built-in logger that lets you track all executed SQL statements and measure the duration of their execution. Activation: + +```php +$database->connect([ + 'driver' => 'sqlite', + 'database' => 'sample.sdb', + 'profiler' => [ + 'file' => 'file.log', + ], +]); +``` + +A more versatile profiler is the Tracy panel, which is activated when connecting to Nette. + + +Connect to [Nette |https://nette.org] +===================================== + +In the configuration file, we register the DI extension and add the `dibi` section - this creates the required objects and also the database panel in the [Tracy |https://tracy.nette.org] debugger bar. + +```neon +extensions: + dibi: Dibi\Bridges\Nette\DibiExtension22 + +dibi: + host: localhost + username: root + password: *** + database: foo + lazy: true +``` + +Then the connection object can be [obtained as a service from the DI container |https://doc.nette.org/di-usage], e.g.: + +```php +class Model +{ + private $database; + + public function __construct(Dibi\Connection $database) + { + $this->database = $database; + } +} +``` + + +Community Extensions +==================== + +Various libraries, ORMs and extensions are built on top of Dibi. You can find a complete list of them on "Packagist":https://packagist.org/packages/dibi/dibi/dependents?order_by=downloads&requires=require. + +{{maintitle: Dibi – Smart Database Abstraction Library for PHP}} diff --git a/dibi/en/@menu.texy b/dibi/en/@menu.texy new file mode 100644 index 0000000000..4add6468f0 --- /dev/null +++ b/dibi/en/@menu.texy @@ -0,0 +1,3 @@ +- [Home | @home] +- "API .[link-external]":https://api.nette.org/dibi/ +- "GitHub .[link-external]":https://github.com/dg/dibi diff --git a/dibi/en/@meta.texy b/dibi/en/@meta.texy new file mode 100644 index 0000000000..b9ca163d2f --- /dev/null +++ b/dibi/en/@meta.texy @@ -0,0 +1 @@ +{{sitename: Dibi Documentation}} diff --git a/dibi/meta.json b/dibi/meta.json new file mode 100644 index 0000000000..ef3653f6bc --- /dev/null +++ b/dibi/meta.json @@ -0,0 +1,5 @@ +{ + "version": "5.x", + "repo": "dg/dibi", + "composer": "dibi/dibi" +} diff --git a/forms/bg/@meta.texy b/forms/bg/@meta.texy new file mode 100644 index 0000000000..57804a1127 --- /dev/null +++ b/forms/bg/@meta.texy @@ -0,0 +1 @@ +{{sitename: Документация на Nette}} diff --git a/forms/cs/@meta.texy b/forms/cs/@meta.texy new file mode 100644 index 0000000000..462d9add80 --- /dev/null +++ b/forms/cs/@meta.texy @@ -0,0 +1 @@ +{{sitename: Nette Dokumentace}} diff --git a/forms/cs/controls.texy b/forms/cs/controls.texy index c8262c9a9d..8b3396fa72 100644 --- a/forms/cs/controls.texy +++ b/forms/cs/controls.texy @@ -441,7 +441,7 @@ U všech prvků můžeme volat následující metody (kompletní přehled v [API .[table-form-methods language-php] | `setDefaultValue($value)` | nastaví výchozí hodnotu -| `getValue()` | získat aktuální hodnotu +| `getValue()` | získá aktuální hodnotu | `setOmitted()` | [#vynechání hodnoty] | `setDisabled()` | [#deaktivace prvků] diff --git a/forms/cs/in-presenter.texy b/forms/cs/in-presenter.texy index 33ac7fa95d..2c827d31f7 100644 --- a/forms/cs/in-presenter.texy +++ b/forms/cs/in-presenter.texy @@ -19,7 +19,7 @@ $form = new Form; $form->addText('name', 'Jméno:'); $form->addPassword('password', 'Heslo:'); $form->addSubmit('send', 'Registrovat'); -$form->onSuccess[] = [$this, 'formSucceeded']; +$form->onSuccess[] = $this->formSucceeded(...); ``` a v prohlížeči se zobrazí takto: @@ -42,11 +42,11 @@ class HomePresenter extends Nette\Application\UI\Presenter $form->addText('name', 'Jméno:'); $form->addPassword('password', 'Heslo:'); $form->addSubmit('send', 'Registrovat'); - $form->onSuccess[] = [$this, 'formSucceeded']; + $form->onSuccess[] = $this->formSucceeded(...); return $form; } - public function formSucceeded(Form $form, $data): void + private function formSucceeded(Form $form, $data): void { // tady zpracujeme data odeslaná formulářem // $data->name obsahuje jméno @@ -303,16 +303,16 @@ Pokud má formulář více než jedno tlačítko, potřebujeme zpravidla rozliš ```php $form->addSubmit('save', 'Uložit') - ->onClick[] = [$this, 'saveButtonPressed']; + ->onClick[] = $this->saveButtonPressed(...); $form->addSubmit('delete', 'Smazat') - ->onClick[] = [$this, 'deleteButtonPressed']; + ->onClick[] = $this->deleteButtonPressed(...); ``` Tyto handlery se volají pouze v případě validně vyplněného formuláře, stejně jako v případě události `onSuccess`. Rozdíl je v tom, že jako první parametr se místo formulář může předat odesílací tlačítko, záleží na typu, který uvedete: ```php -public function saveButtonPressed(Nette\Forms\Controls\Button $button, $data) +private function saveButtonPressed(Nette\Forms\Controls\Button $button, $data) { $form = $button->getForm(); // ... @@ -403,7 +403,7 @@ protected function createComponentSignInForm(): Form $form = $this->formFactory->create(); // můžeme formulář pozměnit, zde například měníme popisku na tlačítku $form['send']->setCaption('Pokračovat'); - $form->onSuccess[] = [$this, 'signInFormSuceeded']; // a přidáme handler + $form->onSuccess[] = $this->signInFormSuceeded(...); // a přidáme handler return $form; } ``` diff --git a/forms/cs/validation.texy b/forms/cs/validation.texy index e313be57b9..479e12df74 100644 --- a/forms/cs/validation.texy +++ b/forms/cs/validation.texy @@ -223,11 +223,11 @@ protected function createComponentSignInForm(): Form { $form = new Form; // ... - $form->onValidate[] = [$this, 'validateSignInForm']; + $form->onValidate[] = $this->validateSignInForm(...); return $form; } -public function validateSignInForm(Form $form, \stdClass $data): void +private function validateSignInForm(Form $form, \stdClass $data): void { if ($data->foo > 1 && $data->bar > 5) { $form->addError('Tato kombinace není možná.'); diff --git a/forms/de/@meta.texy b/forms/de/@meta.texy new file mode 100644 index 0000000000..b3b806b2ca --- /dev/null +++ b/forms/de/@meta.texy @@ -0,0 +1 @@ +{{sitename: Nette Dokumentation}} diff --git a/forms/el/@meta.texy b/forms/el/@meta.texy new file mode 100644 index 0000000000..88e29852c7 --- /dev/null +++ b/forms/el/@meta.texy @@ -0,0 +1 @@ +{{sitename: Nette Τεκμηρίωση}} diff --git a/forms/en/@meta.texy b/forms/en/@meta.texy new file mode 100644 index 0000000000..42471908b0 --- /dev/null +++ b/forms/en/@meta.texy @@ -0,0 +1 @@ +{{sitename: Nette Documentation}} diff --git a/forms/en/in-presenter.texy b/forms/en/in-presenter.texy index a1543bcaa1..b4cde43641 100644 --- a/forms/en/in-presenter.texy +++ b/forms/en/in-presenter.texy @@ -19,14 +19,14 @@ $form = new Form; $form->addText('name', 'Name:'); $form->addPassword('password', 'Password:'); $form->addSubmit('send', 'Sign up'); -$form->onSuccess[] = [$this, 'formSucceeded']; +$form->onSuccess[] = $this->formSucceeded(...); ``` and in the browser, it will be displayed like this: [* form-en.webp *] -A form in a presenter is an object of the `Nette\Application\UI\Form` class; its predecessor `Nette\Forms\Form` is intended for standalone use. We added controls named name, password, and a submit button. Finally, the line `$form->onSuccess[] = [$this, 'formSucceeded'];` states that after submission and successful validation, the method `$this->formSucceeded()` should be called. +A form in a presenter is an object of the `Nette\Application\UI\Form` class; its predecessor `Nette\Forms\Form` is intended for standalone use. We added controls named name, password, and a submit button. Finally, the line `$form->onSuccess` states that after submission and successful validation, the method `$this->formSucceeded()` should be called. From the presenter's perspective, the form is a regular component. Therefore, it is treated as a component and integrated into the presenter using a [factory method |application:components#Factory Methods]. It will look like this: @@ -42,11 +42,11 @@ class HomePresenter extends Nette\Application\UI\Presenter $form->addText('name', 'Name:'); $form->addPassword('password', 'Password:'); $form->addSubmit('send', 'Sign up'); - $form->onSuccess[] = [$this, 'formSucceeded']; + $form->onSuccess[] = $this->formSucceeded(...); return $form; } - public function formSucceeded(Form $form, $data): void + private function formSucceeded(Form $form, $data): void { // here we will process the data sent by the form // $data->name contains name @@ -303,16 +303,16 @@ If the form has more than one button, we usually need to distinguish which one w ```php $form->addSubmit('save', 'Save') - ->onClick[] = [$this, 'saveButtonPressed']; + ->onClick[] = $this->saveButtonPressed(...); $form->addSubmit('delete', 'Delete') - ->onClick[] = [$this, 'deleteButtonPressed']; + ->onClick[] = $this->deleteButtonPressed(...); ``` These handlers are called only if the form is validly filled (unless validation is disabled for the button), just like the `onSuccess` event. The difference is that the first parameter passed can be the submit button object instead of the form, depending on the type hint you specify: ```php -public function saveButtonPressed(Nette\Forms\Controls\Button $button, $data) +private function saveButtonPressed(Nette\Forms\Controls\Button $button, $data) { $form = $button->getForm(); // ... @@ -403,7 +403,7 @@ protected function createComponentSignInForm(): Form $form = $this->formFactory->create(); // we can change the form, here for example we change the label on the button $form['login']->setCaption('Continue'); - $form->onSuccess[] = [$this, 'signInFormSubmitted']; // and add handler + $form->onSuccess[] = $this->signInFormSubmitted(...); // and add handler return $form; } ``` diff --git a/forms/en/validation.texy b/forms/en/validation.texy index 0c32b3bb85..d9a9626cc6 100644 --- a/forms/en/validation.texy +++ b/forms/en/validation.texy @@ -223,11 +223,11 @@ protected function createComponentSignInForm(): Form { $form = new Form; // ... - $form->onValidate[] = [$this, 'validateSignInForm']; + $form->onValidate[] = $this->validateSignInForm(...); return $form; } -public function validateSignInForm(Form $form, \stdClass $data): void +private function validateSignInForm(Form $form, \stdClass $data): void { if ($data->foo > 1 && $data->bar > 5) { $form->addError('This combination is not possible.'); diff --git a/forms/es/@meta.texy b/forms/es/@meta.texy new file mode 100644 index 0000000000..1670b124ad --- /dev/null +++ b/forms/es/@meta.texy @@ -0,0 +1 @@ +{{sitename: Nette Documentación}} diff --git a/forms/fr/@meta.texy b/forms/fr/@meta.texy new file mode 100644 index 0000000000..72ae4b8db8 --- /dev/null +++ b/forms/fr/@meta.texy @@ -0,0 +1 @@ +{{sitename: Documentation Nette}} diff --git a/forms/hu/@meta.texy b/forms/hu/@meta.texy new file mode 100644 index 0000000000..c172d1cda5 --- /dev/null +++ b/forms/hu/@meta.texy @@ -0,0 +1 @@ +{{sitename: Nette dokumentáció}} diff --git a/forms/it/@meta.texy b/forms/it/@meta.texy new file mode 100644 index 0000000000..4647d0c8a2 --- /dev/null +++ b/forms/it/@meta.texy @@ -0,0 +1 @@ +{{sitename: Documentazione Nette}} diff --git a/forms/ja/@meta.texy b/forms/ja/@meta.texy new file mode 100644 index 0000000000..d3c41dc3d7 --- /dev/null +++ b/forms/ja/@meta.texy @@ -0,0 +1 @@ +{{sitename: Nette ドキュメンテーション}} diff --git a/forms/pl/@meta.texy b/forms/pl/@meta.texy new file mode 100644 index 0000000000..61ac92d1af --- /dev/null +++ b/forms/pl/@meta.texy @@ -0,0 +1 @@ +{{sitename: Dokumentacja Nette}} diff --git a/forms/pt/@meta.texy b/forms/pt/@meta.texy new file mode 100644 index 0000000000..41a853b6aa --- /dev/null +++ b/forms/pt/@meta.texy @@ -0,0 +1 @@ +{{sitename: Documentação Nette}} diff --git a/forms/ro/@meta.texy b/forms/ro/@meta.texy new file mode 100644 index 0000000000..9c744b37d6 --- /dev/null +++ b/forms/ro/@meta.texy @@ -0,0 +1 @@ +{{sitename: Documentație Nette}} diff --git a/forms/ru/@meta.texy b/forms/ru/@meta.texy new file mode 100644 index 0000000000..7f329adfce --- /dev/null +++ b/forms/ru/@meta.texy @@ -0,0 +1 @@ +{{sitename: Документация Nette}} diff --git a/forms/sl/@meta.texy b/forms/sl/@meta.texy new file mode 100644 index 0000000000..724324bee5 --- /dev/null +++ b/forms/sl/@meta.texy @@ -0,0 +1 @@ +{{sitename: Nette Dokumentacija}} diff --git a/forms/tr/@meta.texy b/forms/tr/@meta.texy new file mode 100644 index 0000000000..8dfe82f311 --- /dev/null +++ b/forms/tr/@meta.texy @@ -0,0 +1 @@ +{{sitename: Nette Dokümantasyonu}} diff --git a/forms/uk/@meta.texy b/forms/uk/@meta.texy new file mode 100644 index 0000000000..96e2d9752a --- /dev/null +++ b/forms/uk/@meta.texy @@ -0,0 +1 @@ +{{sitename: Документація Nette}} diff --git a/http/bg/@meta.texy b/http/bg/@meta.texy new file mode 100644 index 0000000000..57804a1127 --- /dev/null +++ b/http/bg/@meta.texy @@ -0,0 +1 @@ +{{sitename: Документация на Nette}} diff --git a/http/cs/@meta.texy b/http/cs/@meta.texy new file mode 100644 index 0000000000..462d9add80 --- /dev/null +++ b/http/cs/@meta.texy @@ -0,0 +1 @@ +{{sitename: Nette Dokumentace}} diff --git a/http/cs/request.texy b/http/cs/request.texy index 5dc90de308..1827f489e0 100644 --- a/http/cs/request.texy +++ b/http/cs/request.texy @@ -184,6 +184,30 @@ $body = $httpRequest->getRawBody(); ``` +getOrigin(): ?UrlImmutable .[method] +------------------------------------ +Vrací origin, ze kterého požadavek přišel. Origin se skládá z protokolu, hostname a portu - například `https://example.com:8080`. Vrací `null`, pokud hlavička origin není přítomna nebo je nastavena na `'null'`. + +```php +$origin = $httpRequest->getOrigin(); +echo $origin; // https://example.com:8080 +echo $origin?->getHost(); // example.com +``` + +Prohlížeč posílá hlavičku `Origin` v následujících případech: +- Požadavky mezi doménami (AJAX volání na jinou doménu) +- POST, PUT, DELETE a další modifikující požadavky +- Požadavky provedené pomocí Fetch API + +Prohlížeč NEPOSÍLÁ hlavičku `Origin` při: +- Běžných GET požadavcích na stejnou doménu (navigace v rámci téže domény) +- Přímé navigaci zadáním URL do adresního řádku +- Požadavcích z jiných klientů než prohlížeče (pokud není ručně přidána) + +.[note] +Na rozdíl od hlavičky `Referer` obsahuje `Origin` pouze schéma, host a port - nikoli celou cestu URL. To ji činí vhodnější pro bezpečnostní kontroly při zachování soukromí uživatele. Hlavička `Origin` se primárně používá pro validaci [CORS |nette:glossary#Cross-Origin Resource Sharing (CORS)] (Cross-Origin Resource Sharing). + + detectLanguage(array $langs): ?string .[method] ----------------------------------------------- Detekuje jazyk. Jako parametr `$lang` předáme pole s jazyky, které aplikace podporuje, a ona vrátí ten, který by viděl návštěvníkův prohlížeč nejraději. Nejsou to žádná kouzla, jen se využívá hlavičky `Accept-Language`. Pokud nedojde k žádné shodě, vrací `null`. @@ -389,6 +413,11 @@ getTemporaryFile(): string .[method] Vrací cestu k dočasné lokaci uploadovaného souboru. V případě, že upload nebyl úspěšný, vrací `''`. +__toString(): string .[method] +------------------------------ +Vrací cestu k dočasnému umístění nahraného souboru. To umožňuje objekt `FileUpload` použít přímo jako řetězec. + + isImage(): bool .[method] ------------------------- Vrací `true`, pokud nahraný soubor je obrázek ve formátu JPEG, PNG, GIF, WebP nebo AVIF. Detekce probíhá na základě jeho signatury a neověřuje se integrita celého souboru. Zda není obrázek poškozený lze zjistit například pokusem o jeho [načtení |#toImage]. diff --git a/http/cs/response.texy b/http/cs/response.texy index baea11f900..4732bc7a76 100644 --- a/http/cs/response.texy +++ b/http/cs/response.texy @@ -34,9 +34,9 @@ isSent(): bool .[method] Vrací, zda už došlo k odeslání hlaviček ze serveru do prohlížeče, a tedy již není možné odesílat hlavičky či měnit stavový kód. -setHeader(string $name, string $value) .[method] ------------------------------------------------- -Odešle HTTP hlavičku a **přepíše** dříve odeslanou hlavičkou stejného jména. +setHeader(string $name, ?string $value) .[method] +------------------------------------------------- +Odešle HTTP hlavičku a **přepíše** dříve odeslanou hlavičkou stejného jména. Pokud je `$value` `null`, bude záhlaví odstraněno. ```php $httpResponse->setHeader('Pragma', 'no-cache'); @@ -115,8 +115,8 @@ $httpResponse->sendAsFile('faktura.pdf'); ``` -setCookie(string $name, string $value, $time, ?string $path=null, ?string $domain=null, ?bool $secure=null, ?bool $httpOnly=null, ?string $sameSite=null) .[method] -------------------------------------------------------------------------------------------------------------------------------------------------------------------- +setCookie(string $name, string $value, $time, ?string $path=null, ?string $domain=null, ?bool $secure=null, ?bool $httpOnly=null, ?string $sameSite='Lax') .[method] +-------------------------------------------------------------------------------------------------------------------------------------------------------------------- Odešle cookie. Výchozí hodnoty parametrů: | `$path` | `'/'` | cookie má dosah na všechny cesty v (sub)doméně *(konfigurovatelné)* diff --git a/http/cs/sessions.texy b/http/cs/sessions.texy index f4ef752aec..de10e7715f 100644 --- a/http/cs/sessions.texy +++ b/http/cs/sessions.texy @@ -23,7 +23,7 @@ Správu session má na starosti objekt [api:Nette\Http\Session], ke kterému se Start session ============= -Nette ve výchozím nastavení automaticky zahájí session automaticky ve chvíli, když z ní začneme číst nebo do ní zapisovat data. Ručně se session zahájí pomocí `$session->start()`. +Nette ve výchozím nastavení automaticky zahájí session ve chvíli, když z ní začneme číst nebo do ní zapisovat data. Ručně se session zahájí pomocí `$session->start()`. PHP odešle při spuštění session HTTP hlavičky ovlivňující kešování, viz [php:session_cache_limiter], a případně i cookie se session ID. Proto je nutné vždy session nastartovat ještě před odesláním jakéhokoliv výstupu do prohlížeče, jinak dojde k vyhození výjimky. Pokud tedy víte, že v průběhu vykreslování stránky se bude používat session, nastartujte ji ručně předtím, třeba v presenteru. diff --git a/http/cs/urls.texy b/http/cs/urls.texy index 9e722a9d7c..e40a157e18 100644 --- a/http/cs/urls.texy +++ b/http/cs/urls.texy @@ -82,6 +82,7 @@ Můžeme pracovat i s jednotlivými query parametry pomocí: |--------------------------------------------------- | `setQuery(string\|array $query)` | `getQueryParameters(): array` | `setQueryParameter(string $name, $val)` | `getQueryParameter(string $name)` +| `appendQuery(string|array $query)` | getDomain(int $level = 2): string .[method] @@ -107,6 +108,11 @@ $url->isEqual('https://nette.org'); ``` +canonicalize() .[method] +------------------------ +Převede URL do kanonického tvaru. To zahrnuje například seřazení parametrů v query stringu podle abecedy, převod hostname na malá písmena a odstranění nadbytečných znaků. + + Url::isAbsolute(string $url): bool .[method]{data-version:3.3.2} ---------------------------------------------------------------- Ověřuje, zda je URL absolutní. URL je považována za absolutní, pokud začíná schématem (např. http, https, ftp) následovaným dvojtečkou. diff --git a/http/de/@meta.texy b/http/de/@meta.texy new file mode 100644 index 0000000000..b3b806b2ca --- /dev/null +++ b/http/de/@meta.texy @@ -0,0 +1 @@ +{{sitename: Nette Dokumentation}} diff --git a/http/el/@meta.texy b/http/el/@meta.texy new file mode 100644 index 0000000000..88e29852c7 --- /dev/null +++ b/http/el/@meta.texy @@ -0,0 +1 @@ +{{sitename: Nette Τεκμηρίωση}} diff --git a/http/en/@meta.texy b/http/en/@meta.texy new file mode 100644 index 0000000000..42471908b0 --- /dev/null +++ b/http/en/@meta.texy @@ -0,0 +1 @@ +{{sitename: Nette Documentation}} diff --git a/http/en/request.texy b/http/en/request.texy index ae45438508..47e0232f54 100644 --- a/http/en/request.texy +++ b/http/en/request.texy @@ -184,6 +184,30 @@ $body = $httpRequest->getRawBody(); ``` +getOrigin(): ?UrlImmutable .[method] +------------------------------------ +Returns the origin from which the request came. An origin consists of the scheme (protocol), hostname, and port - for example, `https://example.com:8080`. Returns `null` if the origin header is not present or is set to `'null'`. + +```php +$origin = $httpRequest->getOrigin(); +echo $origin; // https://example.com:8080 +echo $origin?->getHost(); // example.com +``` + +The browser sends the `Origin` header in the following cases: +- Cross-origin requests (AJAX calls to a different domain) +- POST, PUT, DELETE, and other modifying requests +- Requests made using the Fetch API + +The browser does NOT send the `Origin` header for: +- Regular GET requests to the same domain (same-origin navigation) +- Direct navigation by typing a URL into the address bar +- Requests from non-browser clients + +.[note] +Unlike the `Referer` header, `Origin` contains only the scheme, host, and port - not the full URL path. This makes it more suitable for security checks while preserving user privacy. The `Origin` header is primarily used for [CORS |nette:glossary#Cross-Origin Resource Sharing (CORS)] (Cross-Origin Resource Sharing) validation. + + detectLanguage(array $langs): ?string .[method] ----------------------------------------------- Detects the language. Pass an array of languages supported by the application as the `$langs` parameter, and it will return the one preferred by the visitor's browser. It's not magic; it just uses the `Accept-Language` header. If no match is found, it returns `null`. @@ -389,6 +413,11 @@ getTemporaryFile(): string .[method] Returns the path to the temporary location of the uploaded file. If the upload was not successful, it returns `''`. +__toString(): string .[method] +------------------------------ +Returns the path to the temporary location of the uploaded file. This allows the `FileUpload` object to be used directly as a string. + + isImage(): bool .[method] ------------------------- Returns `true` if the uploaded file is a JPEG, PNG, GIF, WebP, or AVIF image. Detection is based on its signature and does not verify the integrity of the entire file. Whether an image is corrupted can be determined, for example, by trying to [load it |#toImage]. diff --git a/http/en/response.texy b/http/en/response.texy index 7654f039e9..7dbd4dca00 100644 --- a/http/en/response.texy +++ b/http/en/response.texy @@ -34,9 +34,9 @@ isSent(): bool .[method] Returns whether headers have already been sent from the server to the browser, meaning it is no longer possible to send headers or change the status code. -setHeader(string $name, string $value) .[method] ------------------------------------------------- -Sends an HTTP header and **overwrites** a previously sent header of the same name. +setHeader(string $name, ?string $value) .[method] +------------------------------------------------- +Sends an HTTP header and **overwrites** a previously sent header of the same name. If `$value` is `null`, the header will be removed. ```php $httpResponse->setHeader('Pragma', 'no-cache'); @@ -115,8 +115,8 @@ $httpResponse->sendAsFile('invoice.pdf'); ``` -setCookie(string $name, string $value, $time, ?string $path=null, ?string $domain=null, ?bool $secure=null, ?bool $httpOnly=null, ?string $sameSite=null) .[method] -------------------------------------------------------------------------------------------------------------------------------------------------------------------- +setCookie(string $name, string $value, $time, ?string $path=null, ?string $domain=null, ?bool $secure=null, ?bool $httpOnly=null, ?string $sameSite='Lax') .[method] +-------------------------------------------------------------------------------------------------------------------------------------------------------------------- Sends a cookie. Default parameter values: | `$path` | `'/'` | cookie is available for all paths within the (sub)domain *(configurable)* diff --git a/http/en/urls.texy b/http/en/urls.texy index 84a947c12f..608fa0064f 100644 --- a/http/en/urls.texy +++ b/http/en/urls.texy @@ -82,6 +82,7 @@ We can also work with individual query parameters using: |--------------------------------------------------- | `setQuery(string\|array $query)` | `getQueryParameters(): array` | `setQueryParameter(string $name, $val)` | `getQueryParameter(string $name)` +| `appendQuery(string|array $query)` | getDomain(int $level = 2): string .[method] @@ -107,6 +108,11 @@ $url->isEqual('https://nette.org'); ``` +canonicalize() .[method] +------------------------ +Converts the URL to canonical form. This includes, for example, sorting the parameters in the query string alphabetically, converting the hostname to lowercase, and removing redundant characters. + + Url::isAbsolute(string $url): bool .[method]{data-version:3.3.2} ---------------------------------------------------------------- Checks if a URL is absolute. A URL is considered absolute if it begins with a scheme (e.g., http, https, ftp) followed by a colon. diff --git a/http/es/@meta.texy b/http/es/@meta.texy new file mode 100644 index 0000000000..1670b124ad --- /dev/null +++ b/http/es/@meta.texy @@ -0,0 +1 @@ +{{sitename: Nette Documentación}} diff --git a/http/fr/@meta.texy b/http/fr/@meta.texy new file mode 100644 index 0000000000..72ae4b8db8 --- /dev/null +++ b/http/fr/@meta.texy @@ -0,0 +1 @@ +{{sitename: Documentation Nette}} diff --git a/http/hu/@meta.texy b/http/hu/@meta.texy new file mode 100644 index 0000000000..c172d1cda5 --- /dev/null +++ b/http/hu/@meta.texy @@ -0,0 +1 @@ +{{sitename: Nette dokumentáció}} diff --git a/http/it/@meta.texy b/http/it/@meta.texy new file mode 100644 index 0000000000..4647d0c8a2 --- /dev/null +++ b/http/it/@meta.texy @@ -0,0 +1 @@ +{{sitename: Documentazione Nette}} diff --git a/http/ja/@meta.texy b/http/ja/@meta.texy new file mode 100644 index 0000000000..d3c41dc3d7 --- /dev/null +++ b/http/ja/@meta.texy @@ -0,0 +1 @@ +{{sitename: Nette ドキュメンテーション}} diff --git a/http/pl/@meta.texy b/http/pl/@meta.texy new file mode 100644 index 0000000000..61ac92d1af --- /dev/null +++ b/http/pl/@meta.texy @@ -0,0 +1 @@ +{{sitename: Dokumentacja Nette}} diff --git a/http/pt/@meta.texy b/http/pt/@meta.texy new file mode 100644 index 0000000000..41a853b6aa --- /dev/null +++ b/http/pt/@meta.texy @@ -0,0 +1 @@ +{{sitename: Documentação Nette}} diff --git a/http/ro/@meta.texy b/http/ro/@meta.texy new file mode 100644 index 0000000000..9c744b37d6 --- /dev/null +++ b/http/ro/@meta.texy @@ -0,0 +1 @@ +{{sitename: Documentație Nette}} diff --git a/http/ru/@meta.texy b/http/ru/@meta.texy new file mode 100644 index 0000000000..7f329adfce --- /dev/null +++ b/http/ru/@meta.texy @@ -0,0 +1 @@ +{{sitename: Документация Nette}} diff --git a/http/sl/@meta.texy b/http/sl/@meta.texy new file mode 100644 index 0000000000..724324bee5 --- /dev/null +++ b/http/sl/@meta.texy @@ -0,0 +1 @@ +{{sitename: Nette Dokumentacija}} diff --git a/http/tr/@meta.texy b/http/tr/@meta.texy new file mode 100644 index 0000000000..8dfe82f311 --- /dev/null +++ b/http/tr/@meta.texy @@ -0,0 +1 @@ +{{sitename: Nette Dokümantasyonu}} diff --git a/http/uk/@meta.texy b/http/uk/@meta.texy new file mode 100644 index 0000000000..96e2d9752a --- /dev/null +++ b/http/uk/@meta.texy @@ -0,0 +1 @@ +{{sitename: Документація Nette}} diff --git a/latte/bg/@menu.texy b/latte/bg/@menu.texy index c0fceec790..c6324fc01c 100644 --- a/latte/bg/@menu.texy +++ b/latte/bg/@menu.texy @@ -5,8 +5,8 @@ diff --git a/latte/bg/@meta.texy b/latte/bg/@meta.texy new file mode 100644 index 0000000000..4297aeff19 --- /dev/null +++ b/latte/bg/@meta.texy @@ -0,0 +1 @@ +{{sitename: Документация на Latte}} diff --git a/latte/bg/cookbook/@home.texy b/latte/bg/cookbook/@home.texy index aef61d9504..019aa6cd32 100644 --- a/latte/bg/cookbook/@home.texy +++ b/latte/bg/cookbook/@home.texy @@ -11,5 +11,3 @@ - [Миграция от PHP |migration-from-php] - [Миграция от Twig |migration-from-twig] - [Използване на Latte със Slim 4 |slim-framework] - -{{leftbar: /@left-menu}} diff --git a/latte/bg/cookbook/@meta.texy b/latte/bg/cookbook/@meta.texy new file mode 100644 index 0000000000..64e87d1168 --- /dev/null +++ b/latte/bg/cookbook/@meta.texy @@ -0,0 +1,2 @@ +{{sitename: Документация на Latte}} +{{leftbar: /@left-menu}} diff --git a/latte/bg/cookbook/grouping.texy b/latte/bg/cookbook/grouping.texy index 94c13cf7c5..fe6ac48fe5 100644 --- a/latte/bg/cookbook/grouping.texy +++ b/latte/bg/cookbook/grouping.texy @@ -249,6 +249,3 @@ {/foreach} ``` - - -{{leftbar: /@left-menu}} diff --git a/latte/bg/cookbook/how-to-write-sql-queries-in-latte.texy b/latte/bg/cookbook/how-to-write-sql-queries-in-latte.texy index 07d0e7a37a..b6a002275e 100644 --- a/latte/bg/cookbook/how-to-write-sql-queries-in-latte.texy +++ b/latte/bg/cookbook/how-to-write-sql-queries-in-latte.texy @@ -38,5 +38,3 @@ $result = $db->query($sql); ``` *Посоченият пример изисква Latte v3.0.5 или по-нова версия.* - -{{leftbar: /@left-menu}} diff --git a/latte/bg/cookbook/migration-from-php.texy b/latte/bg/cookbook/migration-from-php.texy index 4b5e21c1e0..73be04cf53 100644 --- a/latte/bg/cookbook/migration-from-php.texy +++ b/latte/bg/cookbook/migration-from-php.texy @@ -2,7 +2,7 @@ ************************* .[perex] -Преобразувате стар проект, написан на чист PHP, към Latte? Имаме за вас инструмент, който ще ви улесни миграцията. [Изпробвайте го онлайн |https://php2latte.nette.org]. +Преобразувате стар проект, написан на чист PHP, към Latte? Имаме за вас инструмент, който ще ви улесни миграцията. [Изпробвайте го онлайн |https://fiddle.nette.org/php2latte/]. Можете да изтеглите инструмента от [GitHub|https://github.com/nette/latte-tools] или да го инсталирате с помощта на Composer: @@ -68,5 +68,3 @@ foreach ($result as $cur_group) { ``` - -{{leftbar: /@left-menu}} diff --git a/latte/bg/cookbook/migration-from-twig.texy b/latte/bg/cookbook/migration-from-twig.texy index 406bb4de13..04e356b464 100644 --- a/latte/bg/cookbook/migration-from-twig.texy +++ b/latte/bg/cookbook/migration-from-twig.texy @@ -2,7 +2,7 @@ ************************** .[perex] -Преобразувате проект, написан на Twig, към по-модерния Latte? Имаме за вас инструмент, който ще ви улесни миграцията. [Изпробвайте го онлайн |https://twig2latte.nette.org]. +Преобразувате проект, написан на Twig, към по-модерния Latte? Имаме за вас инструмент, който ще ви улесни миграцията. [Изпробвайте го онлайн |https://fiddle.nette.org/twig2latte/]. Можете да изтеглите инструмента от [GitHub|https://github.com/nette/latte-tools] или да го инсталирате с помощта на Composer: @@ -77,5 +77,3 @@ php twig-to-latte.php input.twig.html [output.latte] ``` - -{{leftbar: /@left-menu}} diff --git a/latte/bg/cookbook/passing-variables.texy b/latte/bg/cookbook/passing-variables.texy index 50d4f9e2c7..4e040e9217 100644 --- a/latte/bg/cookbook/passing-variables.texy +++ b/latte/bg/cookbook/passing-variables.texy @@ -156,6 +156,3 @@ $latte->render('template.latte', ['userName' => 'Jan', 'userAge' => 30]); ```latte {sandbox 'secure.latte', data: $secureData} ``` - - -{{leftbar: /@left-menu}} diff --git a/latte/bg/cookbook/slim-framework.texy b/latte/bg/cookbook/slim-framework.texy index d36036bc14..3f72e4bcb4 100644 --- a/latte/bg/cookbook/slim-framework.texy +++ b/latte/bg/cookbook/slim-framework.texy @@ -155,4 +155,3 @@ Three ``` {{priority: -1}} -{{leftbar: /@left-menu}} diff --git a/latte/bg/custom-tags.texy b/latte/bg/custom-tags.texy index 46bbf08171..23b5b4e001 100644 --- a/latte/bg/custom-tags.texy +++ b/latte/bg/custom-tags.texy @@ -923,7 +923,7 @@ class MyLatteExtension extends Extension Генериран HTML: -```html +```latte Изтриване ``` diff --git a/latte/bg/safety-first.texy b/latte/bg/safety-first.texy index 56a3b9fd91..6c7b2d9e1f 100644 --- a/latte/bg/safety-first.texy +++ b/latte/bg/safety-first.texy @@ -33,7 +33,7 @@ echo '

Резултати от търсенето за ' . $search . 'alert("Hacked!")`. Тъй като изходът не е обработен по никакъв начин, той става част от показаната страница: -```html +```latte

Резултати от търсенето за

``` @@ -59,7 +59,7 @@ echo '' . $imageAlt . ''; На нападателя е достатъчно като описание да вмъкне умело съставен низ `" onload="alert('Hacked!')` и ако изписването не е обработено, резултатният код ще изглежда така: -```html +```latte ``` @@ -91,7 +91,7 @@ echo '' . $imageAlt . ''; Какво точно се разбира под думата контекст? Това е място в документа със собствени правила за обработка на извежданите данни. Зависи от типа на документа (HTML, XML, CSS, JavaScript, plain text, ...) и може да се различава в конкретните му части. Например в HTML документ има цяла редица такива места (контексти), където важат много различни правила. Може би ще се изненадате колко са. Ето първите четири: -```html +```latte

#текст

@@ -108,7 +108,7 @@ echo '' . $imageAlt . ''; Контекстите също могат да се наслояват, което се случва, когато вмъкнем JavaScript или CSS в HTML. Това може да се направи по два различни начина, с елемент и с атрибут: -```html +```latte @@ -132,7 +132,7 @@ echo '' . $imageAlt . ''; Ако го извеждате в HTML текст, точно в този случай не е необходимо да правите никакви замени, защото низът не съдържа нито един знак със специално значение. Друга ситуация възниква, ако го изведете вътре в HTML атрибут, ограден с единични кавички. В такъв случай е необходимо да екранирате кавичките в HTML ентичности: -```html +```latte
``` @@ -152,13 +152,13 @@ alert('Rock\'n\'Roll'); Ако този код вмъкнем в HTML документ с помощта на ` ``` Ако обаче искахме да го вмъкнем в HTML атрибут, трябва още да екранираме кавичките в HTML ентичности: -```html +```latte
``` @@ -170,7 +170,7 @@ https://example.org/?a=Jazz&b=Rock%27n%27Roll И когато този низ изведем в атрибут, ще приложим още екраниране според този контекст и ще заменим `&` с `&`: -```html +```latte ``` @@ -314,7 +314,7 @@ Latte вижда шаблона по същия начин като вас. Ра Нападателят като описание на изображението вмъква умело съставен низ `foo onload=alert('Hacked!')`. Вече знаем, че Twig не може да разпознае дали променливата се извежда в потока на HTML текста, вътре в атрибут, HTML коментар и т.н., накратко не разграничава контексти. И само механично преобразува знаците `< > & ' "` в HTML ентичности. Така резултатният код ще изглежда така: -```html +```latte foo ``` @@ -330,7 +330,7 @@ Latte вижда шаблона по същия начин като вас. Ра Latte вижда шаблона по същия начин като вас. За разлика от Twig, разбира HTML и знае, че променливата се извежда като стойност на атрибут, който не е в кавички. Затова ги допълва. Когато нападателят вмъкне същото описание, резултатният код ще изглежда така: -```html +```latte foo onload=alert('Hacked!') ``` diff --git a/latte/bg/type-system.texy b/latte/bg/type-system.texy index 8f052cf074..aa1be010a5 100644 --- a/latte/bg/type-system.texy +++ b/latte/bg/type-system.texy @@ -21,7 +21,7 @@ class CatalogTemplateParameters { public function __construct( - public string $langs, + public string $lang, /** @var ProductEntity[] */ public array $products, public Address $address, @@ -35,7 +35,7 @@ $latte->render('template.latte', new CatalogTemplateParameters( )); ``` -След това в началото на шаблона поставете тага `{templateType}` с пълното име на класа (включително namespace). Това дефинира, че в шаблона има променливи `$langs` и `$products`, включително съответните типове. Типовете на локалните променливи можете да посочите с помощта на таговете [`{var}` |tags#var default], `{varType}`, [`{define}` |template-inheritance#Дефиниции]. +След това в началото на шаблона поставете тага `{templateType}` с пълното име на класа (включително namespace). Това дефинира, че в шаблона има променливи `$lang` и `$products`, включително съответните типове. Типовете на локалните променливи можете да посочите с помощта на таговете [`{var}` |tags#var default], `{varType}`, [`{define}` |template-inheritance#Дефиниции]. От този момент IDE може да ви подсказва правилно. diff --git a/latte/cs/@left-menu.texy b/latte/cs/@left-menu.texy index 31a85bcaf7..4556b26913 100644 --- a/latte/cs/@left-menu.texy +++ b/latte/cs/@left-menu.texy @@ -5,6 +5,7 @@ - [Dědičnost šablon |Template Inheritance] - [Typový systém |type-system] - [Sandbox] + - [HTML attributy |html-attributes] - Pro designéry 🎨 - [Syntaxe |syntax] diff --git a/latte/cs/@menu.texy b/latte/cs/@menu.texy index bf9ac4aa30..0901dda7ed 100644 --- a/latte/cs/@menu.texy +++ b/latte/cs/@menu.texy @@ -5,8 +5,8 @@ diff --git a/latte/cs/@meta.texy b/latte/cs/@meta.texy new file mode 100644 index 0000000000..4e9560c408 --- /dev/null +++ b/latte/cs/@meta.texy @@ -0,0 +1 @@ +{{sitename: Latte Dokumentace}} diff --git a/latte/cs/cookbook/@home.texy b/latte/cs/cookbook/@home.texy index 60b8f0fba1..b6af15e673 100644 --- a/latte/cs/cookbook/@home.texy +++ b/latte/cs/cookbook/@home.texy @@ -8,9 +8,8 @@ Příklady kódů a receptů pro provádění běžných úkolů pomocí Latte. - [Předávání proměnných napříč šablonami |passing-variables] - [Všechno, co jste kdy chtěli vědět o seskupování |grouping] - [Jak psát SQL queries v Latte? |how-to-write-sql-queries-in-latte] +- [Migrace z Latte 3.0 |migration-from-latte-30] - [Migrace z Latte 2 |migration-from-latte2] - [Migrace z PHP |migration-from-php] - [Migrace z Twigu |migration-from-twig] - [Použití Latte se Slim 4 |slim-framework] - -{{leftbar: /@left-menu}} diff --git a/latte/cs/cookbook/@meta.texy b/latte/cs/cookbook/@meta.texy new file mode 100644 index 0000000000..021702282f --- /dev/null +++ b/latte/cs/cookbook/@meta.texy @@ -0,0 +1,2 @@ +{{sitename: Latte Dokumentace}} +{{leftbar: /@left-menu}} diff --git a/latte/cs/cookbook/grouping.texy b/latte/cs/cookbook/grouping.texy index bebd2a54a5..bdb563efb5 100644 --- a/latte/cs/cookbook/grouping.texy +++ b/latte/cs/cookbook/grouping.texy @@ -249,6 +249,3 @@ Dejme tomu, že v tabulce bude ještě další sloupec `subcategoryId` a kromě {/foreach} ``` - - -{{leftbar: /@left-menu}} diff --git a/latte/cs/cookbook/how-to-write-sql-queries-in-latte.texy b/latte/cs/cookbook/how-to-write-sql-queries-in-latte.texy index 409ab586bb..8607366729 100644 --- a/latte/cs/cookbook/how-to-write-sql-queries-in-latte.texy +++ b/latte/cs/cookbook/how-to-write-sql-queries-in-latte.texy @@ -38,5 +38,3 @@ $result = $db->query($sql); ``` *Uvedený příklad vyžaduje Latte v3.0.5 nebo vyšší.* - -{{leftbar: /@left-menu}} diff --git a/latte/cs/cookbook/migration-from-latte-30.texy b/latte/cs/cookbook/migration-from-latte-30.texy new file mode 100644 index 0000000000..03211a226d --- /dev/null +++ b/latte/cs/cookbook/migration-from-latte-30.texy @@ -0,0 +1,109 @@ +Migrace z Latte 3.0 +******************* + +.[perex] +Latte 3.1 přináší několik vylepšení a změn, díky kterým je psaní šablon bezpečnější a pohodlnější. Většina změn je zpětně kompatibilní, ale některé vyžadují pozornost při přechodu. Tento průvodce shrnuje BC breaky a jak je řešit. + +Latte 3.1 vyžaduje **PHP 8.2** nebo novější. + + +Chytré atributy a migrace +========================= + +Nejvýznamnější změnou v Latte 3.1 je nové chování [chytrých atributů |/html-attributes]. To ovlivňuje, jak se vykreslují hodnoty `null` a logické hodnoty v `data-` atributech. + +1. **Hodnoty `null`:** Dříve se `title={$null}` vykresloval jako `title=""`. Nyní se atribut zcela vynechá. +2. **`data-` atributy:** Dříve se `data-foo={=true}` / `data-foo={=false}` vykreslovaly jako `data-foo="1"` / `data-foo=""`. Nyní se vykreslují jako `data-foo="true"` / `data-foo="false"`. + +Abychom vám pomohli identifikovat místa, kde se výstup ve vaší aplikaci změnil, Latte poskytuje migrační nástroj. + + +Migrační varování +----------------- + +Můžete zapnout [migrační varování |/develop#Migrační varování], která vás během vykreslování upozorní, pokud se výstup liší od Latte 3.0. + +```php +$latte = new Latte\Engine; +$latte->setFeature(Latte\Feature::MigrationWarnings); +``` + +Pokud jsou povolena, sledujte logy aplikace nebo Tracy bar pro `E_USER_WARNING`. Každé varování bude ukazovat na konkrétní řádek a sloupec v šabloně. + +**Jak varování vyřešit:** + +Pokud je nové chování správné (např. chcete, aby prázdný atribut zmizel), potvrďte jej použitím filtru `|accept` pro potlačení varování: + +```latte +
+``` + +Pokud chcete atribut zachovat jako prázdný (např. `title=""`) místo jeho vynechání, použijte null coalescing operátor: + +```latte +
+``` + +Nebo, pokud striktně vyžadujete staré chování (např. `"1"` pro `true`), explicitně přetypujte hodnotu na string: + +```latte +
+``` + +**Poté, co vyřešíte všechna varování:** + +Jakmile vyřešíte všechna varování, vypněte migrační varování a **odstraňte všechny** filtry `|accept` ze svých šablon, protože již nejsou potřeba. + + +Strict Types +============ + +Latte 3.1 zapíná `declare(strict_types=1)` ve výchozím nastavení pro všechny kompilované šablony. To zlepšuje typovou bezpečnost, ale může způsobit typové chyby v PHP výrazech uvnitř šablon, pokud jste spoléhali na volné typování. + +Pokud typy nemůžete opravit okamžitě, můžete toto chování vypnout: + +```php +$latte->setFeature(Latte\Feature::StrictTypes, false); +``` + + +Globální konstanty +================== + +Parser šablon byl vylepšen, aby lépe rozlišoval mezi jednoduchými řetězci a konstantami. V důsledku toho musí být globální konstanty nyní prefixovány zpětným lomítkem `\`. + +```latte +{* Starý způsob (vyhodí varování, v budoucnu bude interpretováno jako string 'PHP_VERSION') *} +{if PHP_VERSION > ...} + +{* Nový způsob (správně interpretováno jako konstanta) *} +{if \PHP_VERSION > ...} +``` + +Tato změna předchází nejednoznačnostem a umožňuje volnější používání neuvodzovkovaných řetězců. + + +Odstraněné funkce +================= + +**Rezervované proměnné:** Proměnné začínající na `$__` (dvou podtržítko) a proměnná `$this` jsou nyní vyhrazeny pro vnitřní použití Latte. Nemůžete je používat v šablonách. + +**Undefined-safe operátor:** Operátor `??->`, což byla specifická funkce Latte vytvořená před PHP 8, byl odstraněn. Jde o historický relikt. Používejte prosím standardní PHP nullsafe operátor `?->`. + +**Filter Loader** +Metoda `Engine::addFilterLoader()` byla označena jako zastaralá a odstraněna. Šlo o nekonzistentní koncept, který se jinde v Latte nevyskytoval. + +**Date Format** +Statická vlastnost `Latte\Runtime\Filters::$dateFormat` byla odstraněna, aby se předešlo globálnímu stavu. + + +Nové funkce +=========== + +Během migrace si můžete začít užívat nové funkce: + +- **Chytré HTML atributy:** Předávání polí do `class` a `style`, automatické vynechání `null` atributů. +- **Nullsafe filtry:** Použijte `{$var?|filter}` pro přeskočení filtrování null hodnot. +- **`n:elseif`:** Nyní můžete používat `n:elseif` společně s `n:if` a `n:else`. +- **Zjednodušená syntaxe:** Pište `
` bez uvozovek. +- **Toggle filtr:** Použijte `|toggle` pro ruční ovládání boolean atributů. diff --git a/latte/cs/cookbook/migration-from-latte2.texy b/latte/cs/cookbook/migration-from-latte2.texy index 3197368dfb..3425b44f2c 100644 --- a/latte/cs/cookbook/migration-from-latte2.texy +++ b/latte/cs/cookbook/migration-from-latte2.texy @@ -302,4 +302,3 @@ class FooNode extends Latte\Compiler\Nodes\StatementNode ``` {{priority: -1}} -{{leftbar: /@left-menu}} diff --git a/latte/cs/cookbook/migration-from-php.texy b/latte/cs/cookbook/migration-from-php.texy index f17181af91..76404b348f 100644 --- a/latte/cs/cookbook/migration-from-php.texy +++ b/latte/cs/cookbook/migration-from-php.texy @@ -2,7 +2,7 @@ Migrace z PHP do Latte ********************** .[perex] -Převádíte starý projekt napsaný v čistém PHP do Latte? Máme pro vás nástroj, které vám migraci usnadní. [Vyzkoušejte jej online |https://php2latte.nette.org]. +Převádíte starý projekt napsaný v čistém PHP do Latte? Máme pro vás nástroj, které vám migraci usnadní. [Vyzkoušejte jej online |https://fiddle.nette.org/php2latte/]. Nástroj si můžete stáhnout z [GitHubu|https://github.com/nette/latte-tools] nebo nainstalovat pomocí Composeru: @@ -68,5 +68,3 @@ Vygeneruje tuto šablonu:
``` - -{{leftbar: /@left-menu}} diff --git a/latte/cs/cookbook/migration-from-twig.texy b/latte/cs/cookbook/migration-from-twig.texy index 7bd031038d..8bc716d5e8 100644 --- a/latte/cs/cookbook/migration-from-twig.texy +++ b/latte/cs/cookbook/migration-from-twig.texy @@ -2,7 +2,7 @@ Migrace z Twigu do Latte ************************ .[perex] -Převádíte projekt napsaný v Twigu do modernějšího Latte? Máme pro vás nástroj, které vám migraci usnadní. [Vyzkoušejte jej online |https://twig2latte.nette.org]. +Převádíte projekt napsaný v Twigu do modernějšího Latte? Máme pro vás nástroj, které vám migraci usnadní. [Vyzkoušejte jej online |https://fiddle.nette.org/twig2latte/]. Nástroj si můžete stáhnout z [GitHubu|https://github.com/nette/latte-tools] nebo nainstalovat pomocí Composeru: @@ -77,5 +77,3 @@ Po konverzi do Latte získáme tuto šablonu: ``` - -{{leftbar: /@left-menu}} diff --git a/latte/cs/cookbook/passing-variables.texy b/latte/cs/cookbook/passing-variables.texy index bdeee636c1..fefbe704ee 100644 --- a/latte/cs/cookbook/passing-variables.texy +++ b/latte/cs/cookbook/passing-variables.texy @@ -156,6 +156,3 @@ Tag `{sandbox}` izoluje šablonu pro bezpečné zpracování. Proměnné jsou p ```latte {sandbox 'secure.latte', data: $secureData} ``` - - -{{leftbar: /@left-menu}} diff --git a/latte/cs/cookbook/slim-framework.texy b/latte/cs/cookbook/slim-framework.texy index c4fa033a3a..f319d69112 100644 --- a/latte/cs/cookbook/slim-framework.texy +++ b/latte/cs/cookbook/slim-framework.texy @@ -155,4 +155,3 @@ Three ``` {{priority: -1}} -{{leftbar: /@left-menu}} diff --git a/latte/cs/custom-filters.texy b/latte/cs/custom-filters.texy index 562d8fd802..299d9c1aae 100644 --- a/latte/cs/custom-filters.texy +++ b/latte/cs/custom-filters.texy @@ -84,7 +84,7 @@ Registrace pomocí rozšíření Pro lepší organizaci, zejména při vytváření znovupoužitelných sad filtrů nebo jejich sdílení jako balíčky, je doporučeným způsobem registrovat je v rámci [rozšíření Latte |extending-latte#Latte Extension]: ```php -namespace App\Latte; +namespace App\Templating; use Latte\Extension; @@ -111,36 +111,12 @@ class MyLatteExtension extends Extension // Registrace $latte = new Latte\Engine; -$latte->addExtension(new App\Latte\MyLatteExtension); +$latte->addExtension(new MyLatteExtension); ``` Tento přístup udrží logiku vašeho filtru zapouzdřenou a registraci jednoduchou. -Použití načítače filtrů ------------------------ - -Latte umožňuje registrovat načítač filtrů pomocí `addFilterLoader()`. Jde o jediné volatelné callable, které Latte požádá o jakýkoliv neznámý název filtru během kompilace. Načítač vrací PHP callable filtru nebo `null`. - -```php -$latte = new Latte\Engine; - -// Načítač může dynamicky vytvářet/získávat callable filtry -$latte->addFilterLoader(function (string $name): ?callable { - if ($name === 'myLazyFilter') { - // Představte si zde náročnou inicializaci... - $service = get_some_expensive_service(); - return fn($value) => $service->process($value); - } - return null; -}); -``` - -Tato metoda byla primárně určena pro líné načítání filtrů s velmi **náročnou inicializací**. Avšak moderní praktiky vkládání závislostí (dependency injection) obvykle zvládají líné služby efektivněji. - -Načítače filtrů přidávají složitost a obecně se nedoporučují ve prospěch přímé registrace pomocí `addFilter()` nebo v rámci rozšíření pomocí `getFilters()`. Používejte načítače pouze pokud máte závažný, specifický důvod související s výkonnostními problémy při inicializaci filtrů, které nelze řešit jinak. - - Filtry používající třídu s atributy ----------------------------------- diff --git a/latte/cs/custom-functions.texy b/latte/cs/custom-functions.texy index 8a1e70f188..1bd18de0e3 100644 --- a/latte/cs/custom-functions.texy +++ b/latte/cs/custom-functions.texy @@ -67,7 +67,7 @@ Registrace pomocí rozšíření Pro lepší organizaci a znovupoužitelnost registrujte funkce v rámci [Latte rozšíření |extending-latte#Latte Extension]. Tento přístup je doporučen pro složitější aplikace nebo sdílené knihovny. ```php -namespace App\Latte; +namespace App\Templating; use Latte\Extension; use Nette\Security\Authorizator; @@ -95,7 +95,7 @@ class MyLatteExtension extends Extension } // Registrace (předpokládáme, že $container obsahuje DIC) -$extension = $container->getByType(App\Latte\MyLatteExtension::class); +$extension = $container->getByType(MyLatteExtension::class); $latte = new Latte\Engine; $latte->addExtension($extension); ``` diff --git a/latte/cs/custom-tags.texy b/latte/cs/custom-tags.texy index bb55513f56..4c35f4c796 100644 --- a/latte/cs/custom-tags.texy +++ b/latte/cs/custom-tags.texy @@ -117,7 +117,7 @@ Vytvořte soubor (např. `DatetimeNode.php`) a definujte třídu: ```php format()`, která sestavuje výsledný řetězec PHP kódu pro kompilovanou šablonu. První argument, `'echo date('Y-m-d H:i:s') %line;'`, je maska, do které jsou doplněny následující parametry. Zástupný symbol `%line` říká metodě `format()`, aby použila druhý argument, kterým je `$this->position`, a vložila komentář jako `/* line 15 */`, který propojuje vygenerovaný PHP kód zpět na původní řádek šablony, což je klíčové pro ladění. -Vlastnost `$this->position` je zděděna ze základní třídy `Node` a je automaticky nastavena parserem Latte. Obsahuje objekt [api:Latte\Compiler\Position], který indikuje, kde byl tag nalezen ve zdrojovém souboru `.latte`. +Vlastnost `$this->position` je zděděna ze základní třídy `Node` a je automaticky nastavena parserem Latte. Obsahuje objekt [api:Latte\Compiler\Range] (potomek třídy `Position` rozšířený o vlastnost `length` v bajtech), který udává, kde se tag v souboru `.latte` nachází. U párových tagů pokrývá rozsah od otevíracího po uzavírací tag a potomci `StatementNode` navíc nabízejí pole `$this->tagRanges` s objekty `Range` pro každý dílčí tag (otevírací, mezilehlé jako `{else}`/`{case}` i uzavírací). Metoda `getIterator()` je zásadní pro kompilační průchody. Musí poskytovat všechny dětské uzly, ale náš jednoduchý `DatetimeNode` aktuálně nemá žádné argumenty ani obsah, tedy žádné dětské uzly. Nicméně metoda musí stále existovat a být generátorem, tj. klíčové slovo `yield` musí být nějakým způsobem přítomno v těle metody. @@ -173,7 +173,7 @@ Nakonec informujme Latte o novém tagu. Vytvořte [třídu rozšíření |extend ```php addExtension(new App\Latte\MyLatteExtension); +$latte->addExtension(new App\Templating\MyLatteExtension); ``` Vytvořte šablonu: @@ -255,7 +255,7 @@ S tímto pochopením upravme metodu `create()` v `DatetimeNode` tak, aby parsova ```php addExtension(new App\Latte\MyLatteExtension($isDev)); +$latte->addExtension(new MyLatteExtension($isDev)); ``` A jeho použití v šabloně: @@ -555,7 +555,7 @@ Upravme `DebugNode::create()` tak, aby očekával `{else}`: ```php Smazat ``` @@ -1003,8 +1003,8 @@ Zástupné symboly `PrintContext::format()` - **`%args`**: Argument musí být `Expression\ArrayNode`. Vypíše položky pole formátované jako argumenty pro volání funkce nebo metody (oddělené čárkami, zpracovává pojmenované argumenty, pokud jsou přítomny). - `$argsNode = new ArrayNode([...]);` - `$context->format('myFunc(%args);', $argsNode)` -> `myFunc(1, name: 'Joe');` -- **`%line`**: Argument musí být objekt `Position` (obvykle `$this->position`). Vkládá PHP komentář `/* line X */` indikující číslo řádku zdroje. - - `$context->format('echo "Hi" %line;', $this->position)` -> `echo "Hi" /* line 42 */;` +- **`%line`**: Argument musí být objekt `Position` (nebo `Range`, obvykle `$this->position`). Vkládá PHP komentář `/* line X */` indikující číslo řádku zdroje. + - `$context->format('echo "Hi" %line;', $this->position)` -> `echo "Hi" /* line 42:1 */;` - **`%escape(...)`**: Generuje PHP kód, který *za běhu* escapuje vnitřní výraz pomocí aktuálních kontextově uvědomělých pravidel escapování. - `$context->format('echo %escape(%node);', $variableNode)` - **`%modify(...)`**: Argument musí být `ModifierNode`. Generuje PHP kód, který aplikuje filtry specifikované v `ModifierNode` na vnitřní obsah, včetně kontextově uvědomělého escapování, pokud není zakázáno pomocí `|noescape`. @@ -1023,7 +1023,7 @@ Zatímco `parseExpression()`, `parseArguments()`, atd., pokrývají mnoho příp ```php setTempDirectory('/path/to/tempdir'); +$latte->setCacheDirectory('/path/to/tempdir'); $params = [ /* proměnné šablony */ ]; // or $params = new TemplateParameters(/* ... */); @@ -57,6 +58,20 @@ $latte->setAutoRefresh(false); Při nasazení na produkčním serveru může prvotní vygenerování cache, zejména u rozsáhlejších aplikací, pochopitelně chviličku trvat. Latte má vestavěnou prevenci před "cache stampede":https://en.wikipedia.org/wiki/Cache_stampede. Jde o situaci, kdy se sejde větší počet souběžných požadavků, které spustí Latte, a protože cache ještě neexistuje, začaly by ji všechny generovat současně. Což by neúměrně zatížilo server. Latte je chytré a při více souběžných požadavcích generuje cache pouze první vlákno, ostatní čekají a následně ji využíjí. +Způsoby rozšíření Latte +======================= + +Latte můžete přizpůsobit hned několika způsoby, od jednoduchých pomocníků až po vlastní jazykové konstrukce. Podrobně se jim věnuje stránka [rozšiřujeme Latte |extending-latte], zde je stručný přehled: + +- **[Vlastní filtry |custom-filters]:** pro formátování nebo transformaci dat ve výstupu šablony (např. `{$var|myFilter}`). +- **[Vlastní funkce |custom-functions]:** pro vlastní logiku, kterou voláte ve výrazech šablony (např. `{myFunction($arg)}`). +- **[Vlastní tagy |custom-tags]:** pro zcela nové jazykové konstrukce (`{mytag}...{/mytag}` nebo `n:mytag`). +- **[Kompilační průchody |compiler-passes]:** funkce, které upravují AST šablony mezi parsováním a generováním PHP kódu (například pro optimalizace nebo bezpečnostní kontroly). +- **[Vlastní loadery |loaders]:** pro změnu způsobu, jakým Latte vyhledává a načítá soubory šablon. + +Pokud chcete svá rozšíření znovu použít v jiných projektech nebo je sdílet s ostatními, zabalte je do třídy [Latte Extension |extending-latte#Latte Extension]. + + Parametry jako třída ==================== @@ -183,16 +198,101 @@ Ve striktním režimu parsování Latte kontroluje, zda nechybí uzavírací HTM ```php $latte = new Latte\Engine; -$latte->setStrictParsing(); +$latte->setFeature(Latte\Feature::StrictParsing); ``` Generování šablon s hlavičkou `declare(strict_types=1)` zapnete takto: ```php $latte = new Latte\Engine; -$latte->setStrictTypes(); +$latte->setFeature(Latte\Feature::StrictTypes); +``` + +.[note] +Od verze Latte 3.1 jsou strict types povoleny ve výchozím nastavení. Můžete je deaktivovat pomocí `$latte->setFeature(Latte\Feature::StrictTypes, false)`. + + +Migrační varování .{data-version:3.1} +===================================== + +Latte 3.1 mění chování některých [HTML atributů|html-attributes]. Například hodnoty `null` nyní odstraní atribut namísto vypsání prázdného řetězce. Abyste snadno našli místa, kde tato změna ovlivňuje vaše šablony, můžete zapnout varování o migraci: + +```php +$latte->setFeature(Latte\Feature::MigrationWarnings); +``` + +Pokud je toto zapnuto, Latte kontroluje vykreslované atributy a vyvolá uživatelské varování (`E_USER_WARNING`), pokud se výstup liší od toho, co by Latte 3.0 vygenerovalo. Když narazíte na varování, použijte jedno z těchto řešení: + +1. Pokud je nový výstup pro váš případ použití správný (např. preferujete, aby atribut zmizel při `null`), potlačte varování přidáním filtru `|accept` +2. Pokud chcete, aby byl atribut vykreslen jako prázdný (např. `title=""`) namísto odstranění, když je proměnná `null`, poskytněte prázdný řetězec jako zálohu: `title={$val ?? ''}` +3. Pokud striktně vyžadujete staré chování (např. vypsání `"1"` pro `true` namísto `"true"`), explicitně přetypujte hodnotu na řetězec: `data-foo={(string) $val}` + +Jakmile jsou všechna varování vyřešena, vypněte varování o migraci a **odstraňte všechny** filtry `|accept` ze svých šablon, protože již nejsou potřeba. + + +Scopované proměnné cyklu .{data-version:3.1.3} +============================================== + +Ve výchozím nastavení zůstávají proměnné definované v cyklu `{foreach}` (jako `$key` a `$value`) dostupné i po jeho skončení – stejně jako v samotném PHP. To může vést k nechtěnému přepsání proměnných, pokud má proměnná cyklu stejný název jako existující proměnná šablony. + +Funkce `ScopedLoopVariables` omezí platnost proměnných na tělo cyklu. Po jeho skončení se obnoví původní hodnota proměnné (pokud existovala), nebo se proměnná odstraní: + +```php +$latte = new Latte\Engine; +$latte->setFeature(Latte\Feature::ScopedLoopVariables); ``` +Příklad rozdílu: + +```latte +{var $item = 'original'} +{foreach [1, 2] as $item}{$item}, {/foreach} +{$item} +``` + +Bez `ScopedLoopVariables`: vypíše `1, 2, 2` (proměnná je přepsána) +Se `ScopedLoopVariables`: vypíše `1, 2, original` (proměnná je obnovena) + +Funguje to i s destrukturováním, např. `{foreach $array as [$a, $b]}`. + +.[note] +Proměnné cyklu používající reference (`{foreach $array as &$value}`) nebo přiřazení do vlastností (`{foreach $array as $obj->prop}`) nejsou scopovány, protože by to narušilo jejich účel. + + +Automatické odsazení (Dedent) .{toc: Dedent}{data-version:3.1.3} +================================================================ + +Při používání párových značek jako `{if}`, `{foreach}` nebo `{block}` se vnořený obsah často odsazuje pro lepší čitelnost. Toto odsazení se ale ve výchozím nastavení přenáší do vygenerovaného výstupu. Funkce `Dedent` ho automaticky odstraní, takže výstup zůstane čistý bez ohledu na úroveň zanoření v šabloně: + +```php +$latte = new Latte\Engine; +$latte->setFeature(Latte\Feature::Dedent); +``` + +Příklad: + +```latte +{if true} + Hello + World +{/if} +``` + +Bez `Dedent` by výstup obsahoval odsazení (`\tHello\n\tWorld\n`). S `Dedent` se odsazení odstraní a výstupem je `Hello\nWorld\n`. + +Hlubší odsazení uvnitř bloku zůstává zachováno relativně k základnímu odsazení: + +```latte +{if true} + Hello + Indented +{/if} +``` + +Výstup: `Hello\n\tIndented\n`. + +Odsazení v bloku musí být konzistentní (buď tabulátory, nebo mezery). Pokud se mísí, Latte vyhodí výjimku `Inconsistent indentation`. + Překládání v šablonách .{toc: TranslatorExtension} ================================================== @@ -266,7 +366,9 @@ Jelikož Latte kompiluje šablony do přehledného PHP kódu, můžete je pohodl Linter: validace syntaxe šablon .{toc: Linter} ============================================== -Projít všechny šablony a zkontrolovat, zda neobsahují syntaktické chyby, vám pomůže nástroj Linter. Spouští se z konzole: +Ke kontrole všech šablon slouží nástroj **Linter**. Jeho úkolem je projít zadané soubory a ověřit, že neobsahují syntaktické chyby ani odkazy na neexistující značky, filtry, funkce, třídy apod. + +Linter se spouští z příkazové řádky: ```shell vendor/bin/latte-lint @@ -274,7 +376,7 @@ vendor/bin/latte-lint Parametrem `--strict` aktivujete [#striktní režim]. -Pokud používáte vlastní značky, vytvořte si také vlastní verzi Linteru, např. `custom-latte-lint`: +Pokud používáte vlastní značky, filtry nebo další rozšíření Latte, je potřeba vytvořit si vlastní variantu Linteru, například `custom-latte-lint`. V té zaregistrujete všechna potřebná rozšíření ještě před samotnou validací šablon: ```php #!/usr/bin/env php @@ -302,6 +404,8 @@ $latte = new Latte\Engine; $linter = new Latte\Tools\Linter(engine: $latte); ``` +Takto přizpůsobený linter pak můžete používat stejným způsobem jako standardní nástroj, ale s plnou znalostí vašich vlastních rozšíření. + Načítání šablon z řetězce ========================= diff --git a/latte/cs/extending-latte.texy b/latte/cs/extending-latte.texy index e155953867..a378ff8cf0 100644 --- a/latte/cs/extending-latte.texy +++ b/latte/cs/extending-latte.texy @@ -44,13 +44,6 @@ $latte->addFilter('truncate', $myTruncate); // Použití v šabloně: {$text|truncate} nebo {$text|truncate:100} ``` -Můžete také zaregistrovat **Filter Loader**, funkci, která dynamicky poskytuje volatelné objekty filtrů podle požadovaného názvu: - -```php -$latte->addFilterLoader(fn(string $name) => /* vrátí volatelný objekt nebo null */); -``` - - Pro registraci funkce použitelné ve výrazech šablony použijte `addFunction()`. ```php diff --git a/latte/cs/filters.texy b/latte/cs/filters.texy index 2e44062ab4..5a53e646d0 100644 --- a/latte/cs/filters.texy +++ b/latte/cs/filters.texy @@ -10,6 +10,9 @@ V šablonách můžeme používat funkce, které pomáhají upravit nebo přefor | `breakLines` | [Před konce řádku přidá HTML odřádkování |#breakLines] | `bytes` | [formátuje velikost v bajtech |#bytes] | `clamp` | [ohraničí hodnotu do daného rozsahu |#clamp] +| `column` | [extrahuje jeden sloupec z pole |#column] +| `commas` | [spojí pole čárkami |#commas] +| `limit` | [omezí délku pole, řetězce nebo iterátoru |#limit] | `dataStream` | [konverze pro Data URI protokol |#dataStream] | `date` | [formátuje datum a čas |#date] | `explode` | [rozdělí řetězec na pole podle oddělovače |#explode] @@ -44,6 +47,7 @@ V šablonách můžeme používat funkce, které pomáhají upravit nebo přefor .[table-latte-filters] |## Velikost písmen | `capitalize` | [malá písmena, první písmeno ve slovech velké |#capitalize] +| `firstLower` | [převede první písmeno na malé |#firstLower] | `firstUpper` | [převede první písmeno na velké |#firstUpper] | `lower` | [převede na malá písmena |#lower] | `upper` | [převede na velká písmena |#upper] @@ -54,6 +58,11 @@ V šablonách můžeme používat funkce, které pomáhají upravit nebo přefor | `floor` | [zaokrouhlí číslo dolů na danou přesnost |#floor] | `round` | [zaokrouhlí číslo na danou přesnost |#round] +.[table-latte-filters] +|## HTML atributy +| `accept` | [potvrzuje nové chování chytrých atributů |#accept] +| `toggle` | [přepíná přítomnost HTML atributu |#toggle] + .[table-latte-filters] |## Escapování | `escapeUrl` | [escapuje parametr v URL |#escapeUrl] @@ -116,10 +125,31 @@ V šabloně se potom volá takto: ``` +Nullsafe filtry .{data-version:3.1} +----------------------------------- + +Jakýkoliv filtr lze učinit nullsafe použitím `?|` místo `|`. Pokud je hodnota `null`, filtr se nevykoná a vrátí se `null`. Filtry následující v řetězci jsou také přeskočeny. + +To je užitečné v kombinaci s HTML atributy, které jsou vynechány, pokud je hodnota `null`. + +```latte +
+{* Pokud je $title null:
*} +{* Pokud je $title 'hello':
*} +``` + + Filtry ====== +accept .[filter]{data-version:3.1} +---------------------------------- +Filtr se používá při [migraci z Latte 3.0|cookbook/migration-from-latte-30] k potvrzení, že jste zkontrolovali změnu chování atributu a akceptujete ji. Nemění hodnotu. + +Jde o dočasný nástroj. Jakmile je migrace dokončena a varování při migraci jsou vypnuta, měli byste tento filtr ze svých šablon odstranit. + + batch(int $length, mixed $item): array .[filter] ------------------------------------------------ Filtr, který zjednodušuje výpis lineárních dat do podoby tabulky. Vrací pole polí se zadaným počtem položek. Pokud zadáte druhý parametr, použije se k doplnění chybějících položek na posledním řádku. @@ -198,7 +228,7 @@ Slova budou začínat velkými písmeny, všechny zbývající znaky budou malá {='i like LATTE'|capitalize} {* vypíše 'I Like Latte' *} ``` -Viz také [#firstUpper], [#lower], [#upper]. +Viz také [#firstLower], [#firstUpper], [#lower], [#upper]. checkUrl .[filter] @@ -232,6 +262,50 @@ Ohraničí hodnotu do daného inkluzivního rozsahu min a max. Existuje také jako [funkce |functions#clamp]. +column(string|int|null $columnKey, string|int|null $indexKey=null) .[filter]{data-version:3.1.3} +------------------------------------------------------------------------------------------------ +Vrátí z vícerozměrného pole hodnoty jednoho sloupce `$columnKey` jako nové pole. Lze použít i na pole objektů pro získání hodnot vlastností. + +```latte +{var $users = [ + [id: 30, name: 'John', age: 30], + [id: 32, name: 'Jane', age: 25], + [id: 33, age: 35], +]} + +{$users|column: 'name'} +{* vrátí ['John', 'Jane'] *} + +{$users|column: 'name', 'id'} +{* vrátí [30 => 'John', 32 => 'Jane'] *} +``` + +Pokud předáte `null` jako klíč sloupce, přeindexuje pole podle `$indexKey`. + + +commas(?string $lastGlue=null) .[filter]{data-version:3.1.3} +------------------------------------------------------------ +Spojí prvky pole čárkou a mezerou (`', '`). Jde o pohodlnou zkratku pro běžný výpis položek v čitelné podobě. + +```latte +{var $items = ['jablka', 'pomeranče', 'banány']} +{$items|commas} +{* vypíše 'jablka, pomeranče, banány' *} +``` + +Lze zadat i vlastní oddělovač pro poslední dvojici položek: + +```latte +{$items|commas: ' a '} +{* vypíše 'jablka, pomeranče a banány' *} + +{=['PHP', 'JavaScript', 'Python']|commas: ', nebo '} +{* vypíše 'PHP, JavaScript, nebo Python' *} +``` + +Viz také [#implode]. + + dataStream(string $mimetype=detect) .[filter] --------------------------------------------- Konvertuje obsah do data URI scheme. Pomocí něj lze do HTML nebo CSS vkládat obrázky bez nutnosti linkovat externí soubory. @@ -324,6 +398,17 @@ Zaokrouhlí číslo dolů na danou přesnost. Viz také [#ceil], [#round]. +firstLower .[filter]{data-version:3.0.22} +----------------------------------------- +Převede první písmeno na malé. Vyžaduje PHP rozšíření `mbstring`. + +```latte +{='The Latte'|firstLower} {* vypíše 'the Latte' *} +``` + +Viz také [#capitalize], [#firstUpper], [#lower], [#upper]. + + firstUpper .[filter] -------------------- Převede první písmeno na velká. Vyžaduje PHP rozšíření `mbstring`. @@ -332,7 +417,7 @@ Převede první písmeno na velká. Vyžaduje PHP rozšíření `mbstring`. {='the latte'|firstUpper} {* vypíše 'The latte' *} ``` -Viz také [#capitalize], [#lower], [#upper]. +Viz také [#capitalize], [#firstLower], [#lower], [#upper]. group(string|int|\Closure $by): array .[filter]{data-version:3.0.16} @@ -369,6 +454,8 @@ Můžete také použít alias `join`: {=[1, 2, 3]|join} {* vypíše '123' *} ``` +Viz také [#commas], [#explode]. + indent(int $level=1, string $char="\t") .[filter] ------------------------------------------------- @@ -490,7 +577,7 @@ Převede řetězec na malá písmena. Vyžaduje PHP rozšíření `mbstring`. {='LATTE'|lower} {* vypíše 'latte' *} ``` -Viz také [#capitalize], [#firstUpper], [#upper]. +Viz také [#capitalize], [#firstLower], [#firstUpper], [#upper]. nocheck .[filter] @@ -599,19 +686,21 @@ Pamatujte, že skutečný vzhled čísel se může lišit podle nastavení země padLeft(int $length, string $pad=' ') .[filter] ----------------------------------------------- -Doplní řetězec do určité délky jiným řetězcem zleva. +Doplní řetězec nebo číslo do určité délky jiným řetězcem zleva. ```latte {='hello'|padLeft: 10, '123'} {* vypíše '12312hello' *} +{=123|padLeft: 5, '0'} {* vypíše '00123' *} ``` padRight(int $length, string $pad=' ') .[filter] ------------------------------------------------ -Doplní řetězec do určité délky jiným řetězcem zprava. +Doplní řetězec nebo číslo do určité délky jiným řetězcem zprava. ```latte {='hello'|padRight: 10, '123'} {* vypíše 'hello12312' *} +{=123|padRight: 5, '0'} {* vypíše '12300' *} ``` @@ -709,14 +798,14 @@ Viz také [#ceil], [#floor]. slice(int $start, ?int $length=null, bool $preserveKeys=false) .[filter] ------------------------------------------------------------------------ -Extrahuje část pole nebo řetězce. +Extrahuje část pole, řetězce nebo iterátoru. ```latte {='hello'|slice: 1, 2} {* vypíše 'el' *} {=['a', 'b', 'c']|slice: 1, 2} {* vypíše ['b', 'c'] *} ``` -Filtr funguje jako funkce PHP `array_slice` pro pole nebo `mb_substr` pro řetězce s fallbackem na funkci `iconv_substr` v režimu UTF‑8. +Filtr funguje jako funkce PHP `array_slice` pro pole nebo `mb_substr` pro řetězce. Pro iterátory vrací generátor – prvky se čtou z původního zdroje jeden po druhém a po dosažení limitu se čtení zastaví. Celý iterátor se do paměti nenačítá. Pokud je start kladný, posloupnost začné posunutá o tento počet od začátku pole/řetezce. Pokud je záporný posloupnost začné posunutá o tolik od konce. @@ -724,6 +813,21 @@ Pokud je zadaný parametr length a je kladný, posloupnost bude obsahovat tolik Ve výchozím nastavení filtr změní pořadí a resetuje celočíselného klíče pole. Toto chování lze změnit nastavením preserveKeys na true. Řetězcové klíče jsou vždy zachovány, bez ohledu na tento parametr. +Viz také [#limit]. + + +limit(int $length) .[filter]{data-version:3.1.3} +------------------------------------------------ +Omezí délku pole, řetězce nebo iterátoru. U polí a iterátorů zachovává klíče. U řetězců respektuje UTF-8. + +```latte +{foreach ($items|limit: 5) as $item} + ... +{/foreach} + +{$text|limit: 100} +``` + sort(?Closure $comparison, string|int|\Closure|null $by=null, string|int|\Closure|bool $byKey=false) .[filter] -------------------------------------------------------------------------------------------------------------- @@ -815,6 +919,21 @@ Extrahuje část řetězce. Tento filtr byl nahrazen filtrem [#slice]. ``` +toggle .[filter]{data-version:3.1} +---------------------------------- +Filtr `toggle` ovládá přítomnost atributu na základě boolean hodnoty. Pokud je hodnota truthy, atribut je přítomen; pokud je falsy, atribut je zcela vynechán: + +```latte +
+{* Pokud je $isGrid truthy:
*} +{* Pokud je $isGrid falsy:
*} +``` + +Tento filtr je užitečný pro vlastní atributy nebo atributy JavaScriptových knihoven, které vyžadují kontrolu přítomnosti/nepřítomnosti podobně jako HTML boolean atributy. + +Filtr lze použít pouze uvnitř HTML atributů. + + translate(...$args) .[filter] ----------------------------- Překládá výrazy do jiných jazyků. Aby byl filtr k dispozici, je potřeba [nastavit překladač |develop#TranslatorExtension]. Můžete také použít [tagy pro překlad |tags#Překlady]. @@ -855,7 +974,7 @@ Převede řetězec na velká písmena. Vyžaduje PHP rozšíření `mbstring`. {='latte'|upper} {* vypíše 'LATTE' *} ``` -Viz také [#capitalize], [#firstUpper], [#lower]. +Viz také [#capitalize], [#firstLower], [#firstUpper], [#lower]. webalize .[filter] diff --git a/latte/cs/functions.texy b/latte/cs/functions.texy index c6d8db5fe2..2931e5583c 100644 --- a/latte/cs/functions.texy +++ b/latte/cs/functions.texy @@ -11,6 +11,7 @@ V šablonách můžeme kromě běžných PHP funkcí používat i tyto další. | `first` | [vrací první prvek pole nebo znak řetězce |#first] | `group` | [seskupí data podle různých kritérií |#group] | `hasBlock` | [zjistí existenci bloku |#hasBlock] +| `hasTemplate`| [zjistí existenci šablony |#hasTemplate] | `last` | [vrací poslední prvek pole nebo znak řetězce |#last] | `odd` | [zkontroluje, zda je dané číslo liché |#odd] | `slice` | [extrahuje část pole nebo řetězce |#slice] @@ -117,6 +118,15 @@ Zjistí, zda blok uvedeného jména existuje: Viz také [kontrola existence bloků |template-inheritance#Kontrola existence bloků]. +hasTemplate(string $name): bool .[method]{data-version:3.0.22} +-------------------------------------------------------------- +Zjistí, zda existuje šablona uvedeného jména: + +```latte +{if hasTemplate('foo.latte')} ... {/if} +``` + + last(string|array $value): mixed .[method] ------------------------------------------ Vrací poslední prvek pole nebo znak řetězce: diff --git a/latte/cs/html-attributes.texy b/latte/cs/html-attributes.texy new file mode 100644 index 0000000000..e9632b2586 --- /dev/null +++ b/latte/cs/html-attributes.texy @@ -0,0 +1,151 @@ +Chytré HTML atributy +******************** + +.[perex] +Latte 3.1 přichází se sadou vylepšení, která se zaměřuje na jednu z nejčastějších činností v šablonách – vypisování HTML atributů. Přináší více pohodlí, flexibility a bezpečnosti. + + +Boolean atributy +================ + +HTML používá speciální atributy jako `checked`, `disabled`, `selected` nebo `hidden`, u kterých nezáleží na konkrétní hodnotě – pouze na jejich přítomnosti. Fungují jako jednoduché příznaky. + +Latte je zpracovává automaticky. Atributu můžete předat jakýkoliv výraz. Pokud je pravdivý (truthy), atribut se vykreslí. Pokud je nepravdivý (falsey - např. `false`, `null`, `0` nebo prázdný řetězec), atribut se zcela vynechá. + +To znamená, že se můžete rozloučit se složitými podmínkami nebo `n:attr` a jednoduše použít: + +```latte + +``` + +Pokud `$isDisabled` je `false` a `$isReadOnly` je `true`, vykreslí se: + +```latte + +``` + +Pokud potřebujete přepínací chování pro standardní atributy, které nemají toto automatické zpracování (tedy např. atributy `data-` nebo `aria-`), použijte filtr [toggle |filters#toggle]. + + +Hodnoty null +============ + +Toto je jedna z nejpříjemnějších změn. Dříve, pokud byla proměnná `null`, vypsala se jako prázdný řetězec `""`. To často vedlo k prázdným atributům v HTML jako `class=""` nebo `title=""`. + +V Latte 3.1 platí nové univerzální pravidlo: **Hodnota `null` znamená, že atribut neexistuje.** + +```latte +
+``` + +Pokud `$title` je `null`, výstupem je `
`. Pokud obsahuje řetězec, např. "Ahoj", výstupem je `
`. Díky tomu nemusíte obalovat atributy do podmínek. + +Pokud používáte filtry, mějte na paměti, že obvykle převádějí `null` na řetězec (např. prázdný řetězec). Abyste tomu zabránili, použijte [nullsafe filtr |filters#Nullsafe filtry] `?|`: + +```latte +
+``` + + +Třídy (Classes) +=============== + +Atributu `class` můžete předat pole. To je ideální pro podmíněné třídy: pokud je pole asociativní, klíče se použijí jako názvy tříd a hodnoty jako podmínky. Třída se vykreslí pouze v případě, že je podmínka splněna. + +```latte + +``` + +Pokud je `$isActive` true, vykreslí se: + +```latte + +``` + +Toto chování není omezeno pouze na `class`. Funguje pro jakýkoliv HTML atribut, který očekává seznam hodnot oddělených mezerou, jako jsou `itemprop`, `rel`, `sandbox` atd. + +```latte + $isExternal]}>odkaz +``` + + +Styly (Styles) +============== + +Atribut `style` také podporuje pole. Je to obzvláště užitečné pro podmíněné styly. Pokud položka pole obsahuje klíč (CSS vlastnost) a hodnotu, vlastnost se vykreslí pouze v případě, že hodnota není `null`. + +```latte +
lightblue, + display => $isVisible ? block : null, + font-size => '16px', +]}>
+``` + +Pokud je `$isVisible` false, vykreslí se: + +```latte +
+``` + + +Data atributy +============= + +Často potřebujeme do HTML předat konfiguraci pro JavaScript. Dříve se to dělalo přes `json_encode`. Nyní můžete atributu `data-` jednoduše předat pole nebo objekt stdClass a Latte jej serializuje do JSONu: + +```latte +
+``` + +Vypíše: + +```latte +
+``` + +Také `true` a `false` se vykreslují jako řetězce `"true"` a `"false"` (tj. validní JSON). + + +Aria atributy +============= + +Specifikace WAI-ARIA vyžaduje textové hodnoty `"true"` a `"false"` pro logické hodnoty. Latte to pro atributy `aria-` řeší automaticky: + +```latte + +``` + +Vypíše: + +```latte + +``` + + +Typová kontrola +=============== + +Už jste někdy viděli `` ve svém vygenerovaném HTML? Je to klasická chyba, která často projde bez povšimnutí. Latte zavádí přísnou typovou kontrolu pro HTML atributy, aby byly vaše šablony vůči takovým přehlédnutím odolnější. + +Latte ví, které atributy jsou které a jaké hodnoty očekávají: + +- **Standardní atributy** (jako `href`, `id`, `value`, `placeholder`...) očekávají hodnotu, kterou lze vykreslit jako text. To zahrnuje řetězce, čísla nebo stringable objekty. Také je akceptováno `null` (atribut vynechá). Pokud však omylem předáte pole, boolean nebo obecný objekt, Latte vyvolá varování a neplatnou hodnotu inteligentně ignoruje. +- **Boolean atributy** (jako `checked`, `disabled`...) akceptují jakýkoliv typ, protože jejich přítomnost je určena logikou pravdivý/nepravdivý. +- **Chytré atributy** (jako `class`, `style`, `data-`...) specificky zpracovávají pole jako validní vstupy. + +Tato kontrola zajišťuje, že vaše aplikace nebude produkovat neočekávané HTML. + + +Migrace z Latte 3.0 +=================== + +Protože se změnilo chování `null` (dříve vypisovalo `""`, nyní atribut vynechá) a atributů `data-` (boolean hodnoty vypisovaly `"1"`/`""`, nyní `"true"`/`"false"`), možná budete muset aktualizovat své šablony. + +Pro hladký přechod poskytuje Latte migrační režim, který upozorňuje na rozdíly. Přečtěte si podrobného průvodce [Migrace z Latte 3.0 na 3.1 |cookbook/migration-from-latte-30]. + +[* html-attributes.webp *] diff --git a/latte/cs/loaders.texy b/latte/cs/loaders.texy index 78797e1d49..17b0f2356e 100644 --- a/latte/cs/loaders.texy +++ b/latte/cs/loaders.texy @@ -105,7 +105,7 @@ getContent(string $name): string .[method] ------------------------------------------ Toto je základní metoda loaderu. Jejím úkolem je získat a vrátit úplný zdrojový kód šablony identifikované pomocí `$name` (jak je předáno metodě `$latte->render()` nebo vráceno metodou [#getReferredName()]). -Pokud šablonu nelze najít nebo k ní přistupovat, tato metoda **musí vyhodit výjimku `Latte\RuntimeException`**. +Pokud šablonu nelze najít nebo k ní přistupovat, tato metoda **musí vyhodit výjimku `Latte\TemplateNotFoundException`**. ```php public function getContent(string $name): string @@ -169,7 +169,7 @@ class DatabaseLoader implements Latte\Loader $stmt->execute([$name]); $content = $stmt->fetchColumn(); if ($content === false) { - throw new Latte\RuntimeException("Template '$name' not found in database."); + throw new Latte\TemplateNotFoundException("Template '$name' not found in database."); } return $content; } diff --git a/latte/cs/recipes.texy b/latte/cs/recipes.texy index a11d147a0e..172a222a08 100644 --- a/latte/cs/recipes.texy +++ b/latte/cs/recipes.texy @@ -7,7 +7,7 @@ Editory a IDE Pište šablony v editoru nebo IDE, který má podporu pro Latte. Bude to mnohem příjemnější. -- PhpStorm: nainstalujte v `Settings > Plugins > Marketplace` [plugin Latte|https://plugins.jetbrains.com/plugin/7457-latte] +- PhpStorm: nainstalujte v `Settings > Plugins > Marketplace` [plugin Latte|https://plugins.jetbrains.com/plugin/24218-latte-support] - VS Code: nainstalujte [Nette Latte + Neon|https://marketplace.visualstudio.com/items?itemName=Kasik96.latte], [Nette Latte templates|https://marketplace.visualstudio.com/items?itemName=smuuf.latte-lang] nebo nejnovější [Nette for VS Code |https://marketplace.visualstudio.com/items?itemName=franken-ui.nette-for-vscode] plugin - NetBeans IDE: nativní podpora Latte je součástí instalace - Sublime Text 3: v Package Control najděte a nainstalujte balíček `Nette` a zvolte Latte ve `View > Syntax` diff --git a/latte/cs/safety-first.texy b/latte/cs/safety-first.texy index e76142ec39..b718215a1b 100644 --- a/latte/cs/safety-first.texy +++ b/latte/cs/safety-first.texy @@ -33,7 +33,7 @@ echo '

Výsledky vyhledávání pro ' . $search . '

'; Útočník může do vyhledávacího políčka a potažmo do proměnné `$search` zapsat libovolný řetězec, tedy i HTML kód jako ``. Protože výstup není nijak ošetřen, stane se součástí zobrazené stránky: -```html +```latte

Výsledky vyhledávání pro

``` @@ -59,7 +59,7 @@ echo '' . $imageAlt . ''; Útočníkovi stačí jako popisek vložit šikovně sestavený řetězec `" onload="alert('Hacked!')` a když vypsání nebude ošetřeno, výsledný kód bude vypadat takto: -```html +```latte ``` @@ -91,7 +91,7 @@ Kontextově sensitivní escapování Co se přesně myslí slovem kontext? Jde o místo v dokumentu s vlastními pravidly pro ošetřování vypisovaných dat. Odvíjí se od typu dokumentu (HTML, XML, CSS, JavaScript, plain text, ...) a může se lišit v jeho konkrétních částech. Například v HTML dokumentu je takových míst (kontextů), kde platí velmi odlišná pravidla, celá řada. Možná budete překvapeni, kolik jich je. Tady máme první čtveřici: -```html +```latte

#text

@@ -108,7 +108,7 @@ Zajímavé je to uvnitř HTML komentářů. Tady se totiž k escapování nepou Kontexty se také mohou vrstvit, k čemuž dochází, když vložíme JavaScript nebo CSS do HTML. To lze udělat dvěma odlišnými způsoby, elementem a atributem: -```html +```latte @@ -132,7 +132,7 @@ Mějme řetězec `Rock'n'Roll`. Pokud jej budete vypisovat v HTML textu, zrovna v tomhle případě netřeba dělat žádné záměny, protože řetězec neobsahuje žádný znak se speciálním významem. Jiná situace nastane, pokud jej vypíšete uvnitř HTML atributu uvozeného do jednoduchých uvozovek. V takovém případě je potřeba escapovat uvozovky na HTML entity: -```html +```latte
``` @@ -152,13 +152,13 @@ alert('Rock\'n\'Roll'); Pokud tento kód vložíme do HTML dokumentu pomocí ` ``` Pokud bychom jej však chtěli vložit do HTML atributu, musíme ještě escapovat uvozovky na HTML entity: -```html +```latte
``` @@ -170,7 +170,7 @@ https://example.org/?a=Jazz&b=Rock%27n%27Roll A když tento řetězec vypíšeme v atributu, ještě aplikujeme escapování podle tohoto kontextu a nahradíme `&` za `&`: -```html +```latte ``` @@ -314,7 +314,7 @@ Všimněte si, že okolo hodnot atributů nejsou uvozovky. Kodér na ně mohl za Útočník jako popisek obrázku vloží šikovně sestavený řetězec `foo onload=alert('Hacked!')`. Už víme, že Twig nemůže poznat, jestli se proměnná vypisuje v toku HTML textu, uvnitř atributu, HTML komentáře, atd., zkrátka nerozlišuje kontexty. A jen mechanicky převádí znaky `< > & ' "` na HTML entity. Takže výsledný kód bude vypadat takto: -```html +```latte foo ``` @@ -330,7 +330,7 @@ Nyní se podíváme, jak si se stejnou šablonou poradí Latte: Latte vidí šablonu stejně jako vy. Na rozdíl od Twigu chápe HTML a ví, že proměnná se vypisuje jako hodnota atributu, který není v uvozovkách. Proto je doplní. Když útočník vloží stejný popisek, výsledný kód bude vypadat takto: -```html +```latte foo onload=alert('Hacked!') ``` diff --git a/latte/cs/syntax.texy b/latte/cs/syntax.texy index ca6e6a2e12..39f1c621de 100644 --- a/latte/cs/syntax.texy +++ b/latte/cs/syntax.texy @@ -2,7 +2,7 @@ Syntaxe ******* .[perex] -Syntax Latte vzešla z praktických požadavků webdesignerů. Hledali jsme tu nejpřívětivější syntax, se kterou elegantně zapíšete i konstrukce, které jinak představují skutečný oříšek. Zároveň všechny výrazy se píší úplně stejně jako v PHP, takže se nemusíte učit nový jazyk. Prostě zúročíte co už dávno umíte. +Syntax Latte vzešla z praktických požadavků webdesignerů. Hledali jsme tu nejpřívětivější syntax, se kterou elegantně zapíšete i konstrukce, které jinak představují skutečný oříšek. Zároveň všechny výrazy se píší úplně stejně jako v PHP, takže se nemusíte učit nový jazyk. Prostě zúročíte, co už dávno umíte. Níže je uvedena minimální šablona, která ilustruje několik základních prvků: tagy, n:atributy, komentáře a filtry. @@ -111,6 +111,34 @@ Což vypíše v závislosti na proměnné `$url`: Avšak n:atributy nejsou jen zkratkou pro párové značky. Existují i ryzí n:atributy, jako třeba [n:href |application:creating-links#V šabloně presenteru] nebo velešikovný pomocník kodéra [n:class |tags#n:class]. +Kromě syntaxe s uvozovkami `
` můžete použít alternativní syntaxi se složenými závorkami `
`. Hlavní výhodou je, že uvnitř `{...}` můžete volně používat jednoduché i dvojité uvozovky: + +```latte +
...
+``` + + +Chytré HTML atributy .{data-version:3.1} +======================================== + +Latte dělá práci se standardními HTML atributy neuvěřitelně snadnou. Za vás řeší boolean atributy jako `checked`, odstraňuje atributy obsahující `null` a umožňuje vám skládat hodnoty `class` a `style` pomocí polí. Dokonce automaticky serializuje data pro `data-` atributy do JSON. + +```latte +{* null odstraní atribut *} +
+ +{* boolean ovládá přítomnost boolean atributů *} + + +{* pole fungují v class *} +
$isActive]}> + +{* pole jsou JSON-enkódována v data- atributech *} +
+``` + +Více informací v samostatné kapitole [Chytré HTML atributy|html-attributes]. + Filtry ====== @@ -148,10 +176,17 @@ Na blok: ``` Nebo přímo na hodnotu (v kombinaci s tagem [`{=expr}` |tags#Vypisování]): + ```latte

{=' Hello world '|trim}

``` +Pokud může být hodnota `null` a chcete v takovém případě zabránit použití filtru, použijte [nullsafe filter |filters#Nullsafe Filters] `?|`: + +```latte +

{$heading?|upper}

+``` + Dynamické HTML značky .{data-version:3.0.9} =========================================== @@ -183,6 +218,41 @@ Uvnitř značek fungují PHP komentáře: ``` +Řízení bílých znaků +=================== + +Latte zachází s bílými znaky inteligentně. Kód můžete volně odsazovat pro čitelnost a výstup zůstane čistý. Když se tag objeví na řádku sám, celý řádek (odsazení i konec řádku) se z výstupu odstraní: + +```latte +
    + {foreach $items as $item} +
  • {$item}
  • + {/foreach} +
+``` + +Vypíše: + +```latte +
    +
  • foo
  • +
  • bar
  • +
+``` + +A co když tag není na řádku sám, ale je tam i další obsah? Bílé znaky před tagem pak patří *dovnitř* tagu: + +```latte +
+ {if $foo}hello{/if} +
+``` + +Odsazení je tedy fakticky uvnitř `{if}`: pokud je `$foo` false, nevypíše se nic – ani odsazení, ani prázdný řádek. Pokud je `$foo` true, výstup přirozeně obsahuje odsazení. Prostě pište přehledně odsazené šablony a výstup bude vždy čistý. + +Pro ještě čistší výstup lze aktivovat funkci [Dedent |develop#Dedent], která odstraní i odsazení vzniklé zanořením v párových značkách jako `{if}` nebo `{foreach}`. + + Syntaktický cukr ================ @@ -204,7 +274,7 @@ Jednoduché řetězce jsou ty, které jsou tvořeny čistě z písmen, číslic, Konstanty --------- -Jelikož lze u jednoduchých řetězců vynechávat uvozovky, doporučujeme pro odlišení zapisovat globální konstanty s lomítkem na začátku: +K rozlišení globálních konstant od jednoduchých řetězců použijte oddělovač globálního jmenného prostoru: ```latte {if \PROJECT_ID === 1} ... {/if} @@ -265,8 +335,6 @@ Historické okénko Latte přišlo v průběhu své historie s celou řadou syntaktických cukříků, které se po pár letech objevily v samotném PHP. Například v Latte bylo možné psát pole jako `[1, 2, 3]` místo `array(1, 2, 3)` nebo používat nullsafe operátor `$obj?->foo` dávno předtím, než to bylo možné v samotném PHP. Latte také zavedlo operátor pro rozbalení pole `(expand) $arr`, který je ekvivalentem dnešního operátoru `...$arr` z PHP. -Undefined-safe operator `??->`, což je obdoba nullsafe operatoru `?->`, který ale nevyvolá chybu pokud proměnná neexistuje, vznikl z historických důvodů a dnes doporučujeme používat standardní PHP operátor `?->`. - Omezení PHP v Latte =================== diff --git a/latte/cs/tags.texy b/latte/cs/tags.texy index b0b7983010..cb8b03378a 100644 --- a/latte/cs/tags.texy +++ b/latte/cs/tags.texy @@ -16,7 +16,7 @@ Přehled a popis všech tagů (neboli značek či maker) šablonovacího systém | `{ifset}` … `{elseifset}` … `{/ifset}` | [podmínka ifset |#ifset elseifset] | `{ifchanged}` … `{/ifchanged}` | [test jestli došlo ke změně |#ifchanged] | `{switch}` `{case}` `{default}` `{/switch}` | [podmínka switch |#switch case default] -| `n:else` | [alternativní obsah pro podmínky |#n:else] +| `n:else`, `n:elseif` | [alternativní obsah pro podmínky |#n:else] .[table-latte-tags language-latte] |## Cykly @@ -97,6 +97,7 @@ Přehled a popis všech tagů (neboli značek či maker) šablonovacího systém | `n:href` | [odkaz používaný v HTML elementech `
` |application:creating-links#V šabloně presenteru] | `{link}` | [vypíše odkaz |application:creating-links#V šabloně presenteru] | `{plink}` | [vypíše odkaz na presenter |application:creating-links#V šabloně presenteru] +| `{linkBase}` | [změna základu pro odkazy |application:creating-links#Změna základu pro odkazy] | `{control}` | [vykreslí komponentu |application:components#Vykreslení] | `{snippet}` … `{/snippet}` | [výstřižek, který lze odeslat AJAXem |application:ajax#Snippety v Latte] | `{snippetArea}` | [obálka pro výstřižky |application:ajax#Oblasti snippetů] @@ -136,7 +137,7 @@ Jako výraz můžete zapsat cokoliv, co znáte z PHP. Nemusíte se zkrátka uči ```latte -{='0' . ($num ?? $num * 3) . ', ' . PHP_VERSION} +{='0' . ($num ?? $num * 3) . ', ' . \PHP_VERSION} ``` Prosím, nehledejte v předchozím příkladu žádný smysl, ale kdybyste tam nějaký našli, napište nám :-) @@ -251,18 +252,20 @@ Víte, že k n:atributům můžete připojit prefix `tag-`? Pak se bude podmínk Boží. -`n:else` .{data-version:3.0.11} -------------------------------- +`n:else` `n:elseif` .{data-version:3.0.11} +------------------------------------------ -Pokud podmínku `{if} ... {/if}` zapíšete v podobě [n:attributu |syntax#n:atributy], máte možnost uvést i alternativní větev pomocí `n:else`: +Pokud podmínku `{if} ... {/if}` zapíšete v podobě [n:attributu |syntax#n:atributy], máte možnost uvést i alternativní větev pomocí `n:else` a `n:elseif` (od Latte 3.1): ```latte Skladem {$count} kusů +Neplatný počet + není dostupné ``` -Atribut `n:else` použít také ve dvojici s [`n:ifset` |#ifset elseifset], [`n:foreach` |#foreach], [`n:try` |#try], [#`n:ifcontent`] a [`n:ifchanged` |#ifchanged]. +Atribut `n:else` lze použít také ve dvojici s [`n:ifset` |#ifset elseifset], [`n:foreach` |#foreach], [`n:try` |#try], [`n:ifcontent` |#n-ifcontent] a [`n:ifchanged` |#ifchanged]. `{/if $cond}` @@ -629,6 +632,8 @@ Název šablony může být jakákoliv výraz v PHP: {include $ajax ? 'ajax.latte' : 'not-ajax.latte'} ``` +Jestli šablona existuje lze ověřit funkcí [`hasTemplate()`|functions#hasTemplate]. + Vložený obsah lze upravit pomocí [filtrů |syntax#Filtry]. Následující příklad odebere všechno HTML a upraví velikost písmen: ```latte @@ -944,6 +949,9 @@ Pomocníci HTML kodéra n:class ------- +.[note] +Od verze Latte 3.1 získal standardní HTML atribut `class` [stejnou funkcionalitu |html-attributes#třídy-classes]. Není tedy již nutné používat n:class. + Díky `n:class` velice snadno vygenerujete HTML atribut `class` přesně podle představ. Příklad: potřebuji, aby aktivní prvek měl třídu `active`: @@ -994,6 +1002,12 @@ V závislosti na vrácených hodnotách vypíše např.: ``` +Funkce inteligentních atributů v Latte 3.1, jako je vynechání hodnot `null` nebo předávání polí do `class` nebo `style`, fungují také v rámci `n:attr`: + +```latte +
+``` + n:tag ----- diff --git a/latte/cs/type-system.texy b/latte/cs/type-system.texy index 0454b2743d..7dcf6e8dce 100644 --- a/latte/cs/type-system.texy +++ b/latte/cs/type-system.texy @@ -21,7 +21,7 @@ Jak začít používat typy? Vytvořte si třídu šablony, např. `CatalogTempl class CatalogTemplateParameters { public function __construct( - public string $langs, + public string $lang, /** @var ProductEntity[] */ public array $products, public Address $address, @@ -35,7 +35,7 @@ $latte->render('template.latte', new CatalogTemplateParameters( )); ``` -A dále na začátek šablony vložte značku `{templateType}` s plným názvem třídy (včetně namespace). To definuje, že v šabloně jsou proměnné `$langs` a `$products` včetně příslušných typů. Typy lokálních proměnných můžete uvést pomocí značek [`{var}` |tags#var default], `{varType}`, [`{define}` |template-inheritance#Definice]. +A dále na začátek šablony vložte značku `{templateType}` s plným názvem třídy (včetně namespace). To definuje, že v šabloně jsou proměnné `$lang` a `$products` včetně příslušných typů. Typy lokálních proměnných můžete uvést pomocí značek [`{var}` |tags#var default], `{varType}`, [`{define}` |template-inheritance#Definice]. Od té chvíle vám může IDE správně našeptávat. diff --git a/latte/de/@menu.texy b/latte/de/@menu.texy index e2e43515e4..b86a1d28cf 100644 --- a/latte/de/@menu.texy +++ b/latte/de/@menu.texy @@ -5,8 +5,8 @@
diff --git a/latte/de/@meta.texy b/latte/de/@meta.texy new file mode 100644 index 0000000000..7b0706e371 --- /dev/null +++ b/latte/de/@meta.texy @@ -0,0 +1 @@ +{{sitename: Latte Dokumentation}} diff --git a/latte/de/cookbook/@home.texy b/latte/de/cookbook/@home.texy index bf7f28e365..c825ee27bb 100644 --- a/latte/de/cookbook/@home.texy +++ b/latte/de/cookbook/@home.texy @@ -11,5 +11,3 @@ Codebeispiele und Rezepte zur Durchführung gängiger Aufgaben mit Latte. - [Migration von PHP |migration-from-php] - [Migration von Twig |migration-from-twig] - [Latte mit Slim 4 verwenden |slim-framework] - -{{leftbar: /@left-menu}} diff --git a/latte/de/cookbook/@meta.texy b/latte/de/cookbook/@meta.texy new file mode 100644 index 0000000000..b1fd0feedb --- /dev/null +++ b/latte/de/cookbook/@meta.texy @@ -0,0 +1,2 @@ +{{sitename: Latte Dokumentation}} +{{leftbar: /@left-menu}} diff --git a/latte/de/cookbook/grouping.texy b/latte/de/cookbook/grouping.texy index 5f6cf416d8..0576348ee5 100644 --- a/latte/de/cookbook/grouping.texy +++ b/latte/de/cookbook/grouping.texy @@ -249,6 +249,3 @@ Angenommen, in der Tabelle gibt es noch eine weitere Spalte `subcategoryId` und {/foreach} ``` - - -{{leftbar: /@left-menu}} diff --git a/latte/de/cookbook/how-to-write-sql-queries-in-latte.texy b/latte/de/cookbook/how-to-write-sql-queries-in-latte.texy index 42ea6a66bd..c9e266a5ba 100644 --- a/latte/de/cookbook/how-to-write-sql-queries-in-latte.texy +++ b/latte/de/cookbook/how-to-write-sql-queries-in-latte.texy @@ -38,5 +38,3 @@ $result = $db->query($sql); ``` *Das angegebene Beispiel erfordert Latte v3.0.5 oder höher.* - -{{leftbar: /@left-menu}} diff --git a/latte/de/cookbook/migration-from-php.texy b/latte/de/cookbook/migration-from-php.texy index 89e20c50da..cf6d12b922 100644 --- a/latte/de/cookbook/migration-from-php.texy +++ b/latte/de/cookbook/migration-from-php.texy @@ -2,7 +2,7 @@ Migration von PHP nach Latte **************************** .[perex] -Konvertieren Sie ein altes Projekt, das in reinem PHP geschrieben ist, nach Latte? Wir haben ein Werkzeug für Sie, das die Migration erleichtert. [Probieren Sie es online aus |https://php2latte.nette.org]. +Konvertieren Sie ein altes Projekt, das in reinem PHP geschrieben ist, nach Latte? Wir haben ein Werkzeug für Sie, das die Migration erleichtert. [Probieren Sie es online aus |https://fiddle.nette.org/php2latte/]. Sie können das Werkzeug von [GitHub|https://github.com/nette/latte-tools] herunterladen oder mit Composer installieren: @@ -68,5 +68,3 @@ Es generiert dieses Template:
``` - -{{leftbar: /@left-menu}} diff --git a/latte/de/cookbook/migration-from-twig.texy b/latte/de/cookbook/migration-from-twig.texy index 866d55f34b..eaeba66ee3 100644 --- a/latte/de/cookbook/migration-from-twig.texy +++ b/latte/de/cookbook/migration-from-twig.texy @@ -2,7 +2,7 @@ Migration von Twig nach Latte ***************************** .[perex] -Konvertieren Sie ein Projekt, das in Twig geschrieben ist, in das modernere Latte? Wir haben ein Werkzeug für Sie, das die Migration erleichtert. [Probieren Sie es online aus |https://twig2latte.nette.org]. +Konvertieren Sie ein Projekt, das in Twig geschrieben ist, in das modernere Latte? Wir haben ein Werkzeug für Sie, das die Migration erleichtert. [Probieren Sie es online aus |https://fiddle.nette.org/twig2latte/]. Sie können das Werkzeug von [GitHub|https://github.com/nette/latte-tools] herunterladen oder mit Composer installieren: @@ -77,5 +77,3 @@ Nach der Konvertierung in Latte erhalten wir dieses Template: ``` - -{{leftbar: /@left-menu}} diff --git a/latte/de/cookbook/passing-variables.texy b/latte/de/cookbook/passing-variables.texy index 6a130f8471..c04d1b9898 100644 --- a/latte/de/cookbook/passing-variables.texy +++ b/latte/de/cookbook/passing-variables.texy @@ -156,6 +156,3 @@ Der Tag `{sandbox}` isoliert ein Template zur sicheren Verarbeitung. Variablen w ```latte {sandbox 'secure.latte', data: $secureData} ``` - - -{{leftbar: /@left-menu}} diff --git a/latte/de/cookbook/slim-framework.texy b/latte/de/cookbook/slim-framework.texy index 2650b70918..6c50daa805 100644 --- a/latte/de/cookbook/slim-framework.texy +++ b/latte/de/cookbook/slim-framework.texy @@ -155,4 +155,3 @@ Three ``` {{priority: -1}} -{{leftbar: /@left-menu}} diff --git a/latte/de/custom-tags.texy b/latte/de/custom-tags.texy index 483b5f5820..89089b627d 100644 --- a/latte/de/custom-tags.texy +++ b/latte/de/custom-tags.texy @@ -923,7 +923,7 @@ Jetzt können Sie `n:confirm` auf Links, Schaltflächen oder Formularelementen v Generiertes HTML: -```html +```latte Löschen ``` diff --git a/latte/de/safety-first.texy b/latte/de/safety-first.texy index 2f5b0697a1..bdc0cb85fa 100644 --- a/latte/de/safety-first.texy +++ b/latte/de/safety-first.texy @@ -33,7 +33,7 @@ echo '

Suchergebnisse für ' . $search . '

'; Ein Angreifer kann in das Suchfeld und somit in die Variable `$search` eine beliebige Zeichenkette eingeben, also auch HTML-Code wie ``. Da die Ausgabe nicht bereinigt wird, wird sie Teil der angezeigten Seite: -```html +```latte

Suchergebnisse für

``` @@ -59,7 +59,7 @@ echo '' . $imageAlt . ''; Dem Angreifer genügt es, als Beschreibung eine geschickt konstruierte Zeichenkette `" onload="alert('Gehackt!')` einzufügen, und wenn die Ausgabe nicht bereinigt wird, sieht der resultierende Code so aus: -```html +```latte ``` @@ -91,7 +91,7 @@ Kontextsensitives Escaping Was genau ist mit dem Wort Kontext gemeint? Es handelt sich um eine Stelle im Dokument mit eigenen Regeln für die Bereinigung ausgegebener Daten. Sie hängt vom Dokumenttyp ab (HTML, XML, CSS, JavaScript, Plain Text, ...) und kann sich in seinen spezifischen Teilen unterscheiden. Beispielsweise gibt es in einem HTML-Dokument eine ganze Reihe solcher Stellen (Kontexte), an denen sehr unterschiedliche Regeln gelten. Vielleicht werden Sie überrascht sein, wie viele es sind. Hier sind die ersten vier: -```html +```latte

#text

@@ -108,7 +108,7 @@ Interessant ist es innerhalb von HTML-Kommentaren. Hier wird nämlich kein Escap Kontexte können sich auch verschachteln, was passiert, wenn wir JavaScript oder CSS in HTML einbetten. Dies kann auf zwei verschiedene Arten geschehen, mit einem Element und einem Attribut: -```html +```latte @@ -132,7 +132,7 @@ Nehmen wir die Zeichenkette `Rock'n'Roll`. Wenn Sie sie im HTML-Text ausgeben, müssen in diesem Fall keine Ersetzungen vorgenommen werden, da die Zeichenkette kein Zeichen mit besonderer Bedeutung enthält. Eine andere Situation ergibt sich, wenn Sie sie innerhalb eines HTML-Attributs ausgeben, das in einfache Anführungszeichen eingeschlossen ist. In diesem Fall müssen die Anführungszeichen in HTML-Entitäten escapet werden: -```html +```latte
``` @@ -152,13 +152,13 @@ alert('Rock\'n\'Roll'); Wenn wir diesen Code mit ` ``` Wenn wir ihn jedoch in ein HTML-Attribut einfügen wollten, müssten wir die Anführungszeichen noch in HTML-Entitäten escapen: -```html +```latte
``` @@ -170,7 +170,7 @@ https://example.org/?a=Jazz&b=Rock%27n%27Roll Und wenn wir diese Zeichenkette in einem Attribut ausgeben, wenden wir noch das Escaping gemäß diesem Kontext an und ersetzen `&` durch `&`: -```html +```latte ``` @@ -314,7 +314,7 @@ Beachten Sie, dass um die Attributwerte keine Anführungszeichen stehen. Der Pro Ein Angreifer fügt als Bildbeschreibung eine geschickt konstruierte Zeichenkette `foo onload=alert('Gehackt!')` ein. Wir wissen bereits, dass Twig nicht erkennen kann, ob die Variable im Fluss des HTML-Textes, innerhalb eines Attributs, eines HTML-Kommentars usw. ausgegeben wird, kurz gesagt, es unterscheidet keine Kontexte. Und konvertiert nur mechanisch die Zeichen `< > & ' "` in HTML-Entitäten. Der resultierende Code sieht also so aus: -```html +```latte foo ``` @@ -330,7 +330,7 @@ Sehen wir uns nun an, wie Latte mit demselben Template umgeht: Latte sieht das Template genauso wie Sie. Im Gegensatz zu Twig versteht es HTML und weiß, dass die Variable als Wert eines Attributs ausgegeben wird, das nicht in Anführungszeichen steht. Deshalb ergänzt es sie. Wenn ein Angreifer dieselbe Beschreibung einfügt, sieht der resultierende Code so aus: -```html +```latte foo onload=alert('Gehackt!') ``` diff --git a/latte/de/type-system.texy b/latte/de/type-system.texy index 88beabecd4..f8994c6ef0 100644 --- a/latte/de/type-system.texy +++ b/latte/de/type-system.texy @@ -21,7 +21,7 @@ Wie beginnt man mit der Verwendung von Typen? Erstellen Sie eine Template-Klasse class CatalogTemplateParameters { public function __construct( - public string $langs, + public string $lang, /** @var ProductEntity[] */ public array $products, public Address $address, @@ -35,7 +35,7 @@ $latte->render('template.latte', new CatalogTemplateParameters( )); ``` -Fügen Sie dann am Anfang des Templates das Tag `{templateType}` mit dem vollständigen Klassennamen (einschließlich Namespace) ein. Dies definiert, dass im Template die Variablen `$langs` und `$products` einschließlich der entsprechenden Typen vorhanden sind. Die Typen lokaler Variablen können Sie mit den Tags [`{var}` |tags#var default], `{varType}`, [`{define}` |template-inheritance#Definition] angeben. +Fügen Sie dann am Anfang des Templates das Tag `{templateType}` mit dem vollständigen Klassennamen (einschließlich Namespace) ein. Dies definiert, dass im Template die Variablen `$lang` und `$products` einschließlich der entsprechenden Typen vorhanden sind. Die Typen lokaler Variablen können Sie mit den Tags [`{var}` |tags#var default], `{varType}`, [`{define}` |template-inheritance#Definition] angeben. Von diesem Moment an kann Ihnen die IDE korrekt Vorschläge machen. diff --git a/latte/el/@menu.texy b/latte/el/@menu.texy index 580aeacd79..76aed7bbd8 100644 --- a/latte/el/@menu.texy +++ b/latte/el/@menu.texy @@ -5,8 +5,8 @@ diff --git a/latte/el/@meta.texy b/latte/el/@meta.texy new file mode 100644 index 0000000000..052351480f --- /dev/null +++ b/latte/el/@meta.texy @@ -0,0 +1 @@ +{{sitename: Latte Τεκμηρίωση}} diff --git a/latte/el/cookbook/@home.texy b/latte/el/cookbook/@home.texy index 7b8d9bbfd7..ca842613f6 100644 --- a/latte/el/cookbook/@home.texy +++ b/latte/el/cookbook/@home.texy @@ -11,5 +11,3 @@ - [Μετάβαση από PHP |migration-from-php] - [Μετάβαση από το Twig |migration-from-twig] - [Χρήση του Latte με το Slim 4 |slim-framework] - -{{leftbar: /@left-menu}} diff --git a/latte/el/cookbook/@meta.texy b/latte/el/cookbook/@meta.texy new file mode 100644 index 0000000000..77b5040a4a --- /dev/null +++ b/latte/el/cookbook/@meta.texy @@ -0,0 +1,2 @@ +{{sitename: Latte Τεκμηρίωση}} +{{leftbar: /@left-menu}} diff --git a/latte/el/cookbook/grouping.texy b/latte/el/cookbook/grouping.texy index 407be804be..ca1f2a72c3 100644 --- a/latte/el/cookbook/grouping.texy +++ b/latte/el/cookbook/grouping.texy @@ -249,6 +249,3 @@ {/foreach} ``` - - -{{leftbar: /@left-menu}} diff --git a/latte/el/cookbook/how-to-write-sql-queries-in-latte.texy b/latte/el/cookbook/how-to-write-sql-queries-in-latte.texy index feed33721c..33fdcb54ad 100644 --- a/latte/el/cookbook/how-to-write-sql-queries-in-latte.texy +++ b/latte/el/cookbook/how-to-write-sql-queries-in-latte.texy @@ -38,5 +38,3 @@ $result = $db->query($sql); ``` *Το παρεχόμενο παράδειγμα απαιτεί Latte v3.0.5 ή νεότερη έκδοση.* - -{{leftbar: /@left-menu}} diff --git a/latte/el/cookbook/migration-from-php.texy b/latte/el/cookbook/migration-from-php.texy index f78daa5f7f..eeedca812b 100644 --- a/latte/el/cookbook/migration-from-php.texy +++ b/latte/el/cookbook/migration-from-php.texy @@ -2,7 +2,7 @@ ************************* .[perex] -Μετατρέπετε ένα παλιό έργο γραμμένο σε καθαρή PHP σε Latte; Έχουμε ένα εργαλείο για εσάς που θα διευκολύνει τη μετάβαση. [Δοκιμάστε το online |https://php2latte.nette.org]. +Μετατρέπετε ένα παλιό έργο γραμμένο σε καθαρή PHP σε Latte; Έχουμε ένα εργαλείο για εσάς που θα διευκολύνει τη μετάβαση. [Δοκιμάστε το online |https://fiddle.nette.org/php2latte/]. Μπορείτε να κατεβάσετε το εργαλείο από το [GitHub|https://github.com/nette/latte-tools] ή να το εγκαταστήσετε χρησιμοποιώντας το Composer: @@ -68,5 +68,3 @@ foreach ($result as $cur_group) {
``` - -{{leftbar: /@left-menu}} diff --git a/latte/el/cookbook/migration-from-twig.texy b/latte/el/cookbook/migration-from-twig.texy index b966722d9a..d81246fc81 100644 --- a/latte/el/cookbook/migration-from-twig.texy +++ b/latte/el/cookbook/migration-from-twig.texy @@ -2,7 +2,7 @@ ************************** .[perex] -Μετατρέπετε ένα έργο γραμμένο σε Twig στο πιο σύγχρονο Latte; Έχουμε ένα εργαλείο για εσάς που θα διευκολύνει τη μετάβαση. [Δοκιμάστε το online |https://twig2latte.nette.org]. +Μετατρέπετε ένα έργο γραμμένο σε Twig στο πιο σύγχρονο Latte; Έχουμε ένα εργαλείο για εσάς που θα διευκολύνει τη μετάβαση. [Δοκιμάστε το online |https://fiddle.nette.org/twig2latte/]. Μπορείτε να κατεβάσετε το εργαλείο από το [GitHub|https://github.com/nette/latte-tools] ή να το εγκαταστήσετε χρησιμοποιώντας το Composer: @@ -77,5 +77,3 @@ twig-to-latte.php input.twig.html [output.latte] ``` - -{{leftbar: /@left-menu}} diff --git a/latte/el/cookbook/passing-variables.texy b/latte/el/cookbook/passing-variables.texy index f505b39780..f25127f334 100644 --- a/latte/el/cookbook/passing-variables.texy +++ b/latte/el/cookbook/passing-variables.texy @@ -156,6 +156,3 @@ $latte->render('template.latte', ['userName' => 'Jan', 'userAge' => 30]); ```latte {sandbox 'secure.latte', data: $secureData} ``` - - -{{leftbar: /@left-menu}} diff --git a/latte/el/cookbook/slim-framework.texy b/latte/el/cookbook/slim-framework.texy index 60c5efd537..0ab57698e9 100644 --- a/latte/el/cookbook/slim-framework.texy +++ b/latte/el/cookbook/slim-framework.texy @@ -155,4 +155,3 @@ final class HomeAction ``` {{priority: -1}} -{{leftbar: /@left-menu}} diff --git a/latte/el/custom-tags.texy b/latte/el/custom-tags.texy index cf69c32588..3c041dd29d 100644 --- a/latte/el/custom-tags.texy +++ b/latte/el/custom-tags.texy @@ -923,7 +923,7 @@ class MyLatteExtension extends Extension Παραγόμενο HTML: -```html +```latte Διαγραφή ``` diff --git a/latte/el/safety-first.texy b/latte/el/safety-first.texy index bb4b7c09d7..65985510ef 100644 --- a/latte/el/safety-first.texy +++ b/latte/el/safety-first.texy @@ -33,7 +33,7 @@ echo '

Αποτελέσματα αναζήτησης για ' . $search . Ένας εισβολέας μπορεί να γράψει στο πεδίο αναζήτησης και κατ' επέκταση στη μεταβλητή `$search` οποιοδήποτε string, δηλαδή και κώδικα HTML όπως ``. Επειδή η έξοδος δεν επεξεργάζεται με κανέναν τρόπο, γίνεται μέρος της εμφανιζόμενης σελίδας: -```html +```latte

Αποτελέσματα αναζήτησης για

``` @@ -59,7 +59,7 @@ echo '' . $imageAlt . ''; Αρκεί ο εισβολέας να εισάγει ως λεζάντα ένα έξυπνα κατασκευασμένο string `" onload="alert('Hacked!')` και αν η εκτύπωση δεν επεξεργαστεί, ο προκύπτων κώδικας θα μοιάζει ως εξής: -```html +```latte ``` @@ -91,7 +91,7 @@ Context-Aware Escaping Τι ακριβώς εννοούμε με τη λέξη context; Πρόκειται για ένα μέρος στο έγγραφο με τους δικούς του κανόνες για την επεξεργασία των εκτυπωμένων δεδομένων. Εξαρτάται από τον τύπο του εγγράφου (HTML, XML, CSS, JavaScript, plain text, ...) και μπορεί να διαφέρει σε συγκεκριμένα μέρη του. Για παράδειγμα, σε ένα έγγραφο HTML, υπάρχουν πολλά τέτοια μέρη (contexts) όπου ισχύουν πολύ διαφορετικοί κανόνες. Ίσως εκπλαγείτε πόσα είναι. Εδώ έχουμε την πρώτη τετράδα: -```html +```latte

#κείμενο

@@ -108,7 +108,7 @@ Context-Aware Escaping Τα contexts μπορούν επίσης να στρωματοποιηθούν, κάτι που συμβαίνει όταν ενσωματώνουμε JavaScript ή CSS σε HTML. Αυτό μπορεί να γίνει με δύο διαφορετικούς τρόπους, με στοιχείο και με attribute: -```html +```latte @@ -132,7 +132,7 @@ Context-Aware Escaping Αν το εκτυπώσετε σε κείμενο HTML, σε αυτή τη συγκεκριμένη περίπτωση δεν χρειάζεται να κάνετε καμία αντικατάσταση, επειδή το string δεν περιέχει κανέναν χαρακτήρα με ειδική σημασία. Η κατάσταση αλλάζει αν το εκτυπώσετε μέσα σε ένα attribute HTML που περικλείεται σε απλά εισαγωγικά. Σε αυτή την περίπτωση, πρέπει να κάνετε escape τα εισαγωγικά σε οντότητες HTML: -```html +```latte
``` @@ -152,13 +152,13 @@ alert('Rock\'n\'Roll'); Αν εισάγουμε αυτόν τον κώδικα σε ένα έγγραφο HTML χρησιμοποιώντας το ` ``` Αν όμως θέλαμε να το εισάγουμε σε ένα attribute HTML, πρέπει ακόμα να κάνουμε escape τα εισαγωγικά σε οντότητες HTML: -```html +```latte
``` @@ -170,7 +170,7 @@ https://example.org/?a=Jazz&b=Rock%27n%27Roll Και όταν εκτυπώνουμε αυτό το string σε ένα attribute, εφαρμόζουμε επιπλέον το escaping σύμφωνα με αυτό το context και αντικαθιστούμε το `&` με `&`: -```html +```latte ``` @@ -314,7 +314,7 @@ Latte εναντίον απλοϊκών συστημάτων Ένας εισβολέας εισάγει ως λεζάντα της εικόνας ένα έξυπνα κατασκευασμένο string `foo onload=alert('Hacked!')`. Γνωρίζουμε ήδη ότι το Twig δεν μπορεί να αναγνωρίσει αν η μεταβλητή εκτυπώνεται στη ροή του κειμένου HTML, μέσα σε ένα attribute, σε ένα σχόλιο HTML κ.λπ., με λίγα λόγια δεν διακρίνει τα contexts. Και απλώς μετατρέπει μηχανικά τους χαρακτήρες `< > & ' "` σε οντότητες HTML. Έτσι, ο προκύπτων κώδικας θα μοιάζει ως εξής: -```html +```latte foo ``` @@ -330,7 +330,7 @@ Latte εναντίον απλοϊκών συστημάτων Το Latte βλέπει το πρότυπο όπως εσείς. Σε αντίθεση με το Twig, καταλαβαίνει HTML και ξέρει ότι η μεταβλητή εκτυπώνεται ως τιμή ενός attribute που δεν βρίσκεται σε εισαγωγικά. Γι' αυτό τα συμπληρώνει. Όταν ο εισβολέας εισάγει την ίδια λεζάντα, ο προκύπτων κώδικας θα μοιάζει ως εξής: -```html +```latte foo onload=alert('Hacked!') ``` diff --git a/latte/el/type-system.texy b/latte/el/type-system.texy index 91b4f29239..26dff347f3 100644 --- a/latte/el/type-system.texy +++ b/latte/el/type-system.texy @@ -21,7 +21,7 @@ class CatalogTemplateParameters { public function __construct( - public string $langs, + public string $lang, /** @var ProductEntity[] */ public array $products, public Address $address, @@ -35,7 +35,7 @@ $latte->render('template.latte', new CatalogTemplateParameters( )); ``` -Και στη συνέχεια, στην αρχή του προτύπου, εισαγάγετε το tag `{templateType}` με το πλήρες όνομα της κλάσης (συμπεριλαμβανομένου του namespace). Αυτό ορίζει ότι στο πρότυπο υπάρχουν οι μεταβλητές `$langs` και `$products` συμπεριλαμβανομένων των αντίστοιχων τύπων τους. Μπορείτε να δηλώσετε τους τύπους των τοπικών μεταβλητών χρησιμοποιώντας τα tags [`{var}` |tags#var default], `{varType}`, [`{define}` |template-inheritance#Ορισμοί define]. +Και στη συνέχεια, στην αρχή του προτύπου, εισαγάγετε το tag `{templateType}` με το πλήρες όνομα της κλάσης (συμπεριλαμβανομένου του namespace). Αυτό ορίζει ότι στο πρότυπο υπάρχουν οι μεταβλητές `$lang` και `$products` συμπεριλαμβανομένων των αντίστοιχων τύπων τους. Μπορείτε να δηλώσετε τους τύπους των τοπικών μεταβλητών χρησιμοποιώντας τα tags [`{var}` |tags#var default], `{varType}`, [`{define}` |template-inheritance#Ορισμοί define]. Από εκείνη τη στιγμή, το IDE σας μπορεί να παρέχει σωστή αυτόματη συμπλήρωση. diff --git a/latte/en/@left-menu.texy b/latte/en/@left-menu.texy index eebab75253..88fc173a96 100644 --- a/latte/en/@left-menu.texy +++ b/latte/en/@left-menu.texy @@ -5,6 +5,7 @@ - [Template Inheritance] - [Type System] - [Sandbox] + - [HTML attributes] - For Designers 🎨 - [Syntax] diff --git a/latte/en/@menu.texy b/latte/en/@menu.texy index c7cb62830e..daad209e3a 100644 --- a/latte/en/@menu.texy +++ b/latte/en/@menu.texy @@ -5,8 +5,8 @@ diff --git a/latte/en/@meta.texy b/latte/en/@meta.texy new file mode 100644 index 0000000000..44994d27ba --- /dev/null +++ b/latte/en/@meta.texy @@ -0,0 +1 @@ +{{sitename: Latte Documentation}} diff --git a/latte/en/cookbook/@home.texy b/latte/en/cookbook/@home.texy index d5407294bc..58b23d4136 100644 --- a/latte/en/cookbook/@home.texy +++ b/latte/en/cookbook/@home.texy @@ -8,9 +8,8 @@ Example codes and recipes for accomplishing common tasks with Latte. - [Passing variables across templates |passing-variables] - [Everything you always wanted to know about grouping |grouping] - [How to write SQL queries in Latte? |how-to-write-sql-queries-in-latte] +- [Migration from Latte 3.0 |migration-from-latte-30] - [Migration from Latte 2 |migration-from-latte2] - [Migration from PHP |migration-from-php] - [Migration from Twig |migration-from-twig] - [Using Latte with Slim 4 |slim-framework] - -{{leftbar: /@left-menu}} diff --git a/latte/en/cookbook/@meta.texy b/latte/en/cookbook/@meta.texy new file mode 100644 index 0000000000..562d8c982e --- /dev/null +++ b/latte/en/cookbook/@meta.texy @@ -0,0 +1,2 @@ +{{sitename: Latte Documentation}} +{{leftbar: /@left-menu}} diff --git a/latte/en/cookbook/grouping.texy b/latte/en/cookbook/grouping.texy index 5154fe54d2..7a8458bb0c 100644 --- a/latte/en/cookbook/grouping.texy +++ b/latte/en/cookbook/grouping.texy @@ -249,6 +249,3 @@ Let's assume the table has another column `subcategoryId`, and besides having ea {/foreach} ``` - - -{{leftbar: /@left-menu}} diff --git a/latte/en/cookbook/how-to-write-sql-queries-in-latte.texy b/latte/en/cookbook/how-to-write-sql-queries-in-latte.texy index d365f71183..bdf6e14bc8 100644 --- a/latte/en/cookbook/how-to-write-sql-queries-in-latte.texy +++ b/latte/en/cookbook/how-to-write-sql-queries-in-latte.texy @@ -38,5 +38,3 @@ $result = $db->query($sql); ``` *This example requires Latte v3.0.5 or higher.* - -{{leftbar: /@left-menu}} diff --git a/latte/en/cookbook/migration-from-latte-30.texy b/latte/en/cookbook/migration-from-latte-30.texy new file mode 100644 index 0000000000..0c73bfce8f --- /dev/null +++ b/latte/en/cookbook/migration-from-latte-30.texy @@ -0,0 +1,110 @@ +Migration from Latte 3.0 +************************ + +.[perex] +Latte 3.1 brings several improvements and changes that make templates safer and more convenient to write. Most changes are backward compatible, but some require attention during migration. This guide summarizes the breaking changes and how to handle them. + +Latte 3.1 requires **PHP 8.2** or newer. + + +Smart Attributes and Migration +============================== + +The most significant change in Latte 3.1 is the new behavior of [Smart Attributes |/html-attributes]. This affects how `null` values and boolean values in `data-` attributes are rendered. + +1. **`null` values:** Previously, `title={$null}` rendered as `title=""`. Now, the attribute is completely dropped. +2. **`data-` attributes:** Previously, `data-foo={=true}` / `data-foo={=false}` rendered as `data-foo="1"` / `data-foo=""`. Now, it renders as `data-foo="true"` / `data-foo="false"`. + +To help you identify places where the output has changed in your application, Latte provides a migration tool. + + +Migration Warnings +------------------ + +You can enable [migration warnings |/develop#Migration Warnings], which will warn you during rendering if the output differs from Latte 3.0. + +```php +$latte = new Latte\Engine; +$latte->setFeature(Latte\Feature::MigrationWarnings); +``` + +When enabled, check your application logs or Tracy bar for `E_USER_WARNING`s. Each warning will point to the specific line, and column in template. + +**How to resolve warnings:** + +If the new behavior is correct (e.g. you want the empty attribute to disappear), confirm it using the `|accept` filter to suppress the warning: + +```latte +
+``` + +If you want to keep the attribute as empty (e.g. `title=""`) instead of dropping it, use the null coalescing operator: + +```latte +
+``` + +Or, if you strictly require the old behavior (e.g. `"1"` for `true`), explicitly cast the value to string: + +```latte +
+``` + +**After you resolve all warnings:** + +Once all warnings are resolved, disable migration warnings and **remove all** `|accept` filters from your templates, as they are no longer needed. + + +Strict Types +============ + +Latte 3.1 enables `declare(strict_types=1)` by default for all compiled templates. This improves type safety but might cause type errors in PHP expressions inside your templates if you were relying on loose typing. + +If you cannot fix the types immediately, you can disable this behavior: + +```php +$latte->setFeature(Latte\Feature::StrictTypes, false); +``` + + +Global Constants +================ + +The template parser has been improved to better distinguish between simple strings and constants. As a result, global constants must now be prefixed with a backslash `\`. + +```latte +{* Old way (throws a warning; in the future will be interpreted as the string 'PHP_VERSION') *} +{if PHP_VERSION > ...} + +{* New way (correctly interpreted as constant) *} +{if \PHP_VERSION > ...} +``` + +This change prevents ambiguity and allows you to use unquoted strings more freely. + + +Removed Features +================ + +**Reserved Variables:** Variables starting with `$__` (double underscore) and the variable `$this` are now strictly reserved for Latte's internal use. You cannot use them in your templates. + +**Undefined-safe Operator:** The `??->` operator, which was a Latte-specific feature created before PHP 8, has been removed. It is a historical relic. Please use the standard PHP nullsafe operator `?->`. + +**Filter Loader** +The `Engine::addFilterLoader()` method has been deprecated and removed. It was an inconsistent concept not found elsewhere in Latte. + +**Date Format** +The static property `Latte\Runtime\Filters::$dateFormat` was removed to avoid global state. + + +New Features +============ + +While migrating, you can start enjoying the new features: + +- **Smart HTML +Attributes:** Pass arrays to `class` and `style`, auto-drop `null` attributes. +- **Nullsafe filters:** Use `{$var?|filter}` to skip filtering null values. +- **`n:elseif`:** You can now use `n:elseif` alongside `n:if` and `n:else`. +- **Simplified syntax:** Write `
` without quotes. +- **Toggle filter:** Use `|toggle` for manual control over boolean attributes. diff --git a/latte/en/cookbook/migration-from-latte2.texy b/latte/en/cookbook/migration-from-latte2.texy index 7fd87dacc6..7df098b91f 100644 --- a/latte/en/cookbook/migration-from-latte2.texy +++ b/latte/en/cookbook/migration-from-latte2.texy @@ -302,4 +302,3 @@ class FooNode extends Latte\Compiler\Nodes\StatementNode ``` {{priority: -1}} -{{leftbar: /@left-menu}} diff --git a/latte/en/cookbook/migration-from-php.texy b/latte/en/cookbook/migration-from-php.texy index 8eb8873dee..9dc5a5ff6a 100644 --- a/latte/en/cookbook/migration-from-php.texy +++ b/latte/en/cookbook/migration-from-php.texy @@ -2,7 +2,7 @@ Migration from PHP to Latte *************************** .[perex] -Are you converting an old project written in pure PHP to Latte? We have a tool to make the migration easier. [Try it out online |https://php2latte.nette.org]. +Are you converting an old project written in pure PHP to Latte? We have a tool to make the migration easier. [Try it out online |https://fiddle.nette.org/php2latte/]. You can download the tool from [GitHub|https://github.com/nette/latte-tools] or install it using Composer: @@ -68,5 +68,3 @@ It generates this template:
``` - -{{leftbar: /@left-menu}} diff --git a/latte/en/cookbook/migration-from-twig.texy b/latte/en/cookbook/migration-from-twig.texy index d7816d607e..1af57367c1 100644 --- a/latte/en/cookbook/migration-from-twig.texy +++ b/latte/en/cookbook/migration-from-twig.texy @@ -2,7 +2,7 @@ Migration from Twig to Latte **************************** .[perex] -Are you converting a project written in Twig to the more modern Latte? We have a tool to make the migration easier. [Try it out online |https://twig2latte.nette.org]. +Are you converting a project written in Twig to the more modern Latte? We have a tool to make the migration easier. [Try it out online |https://fiddle.nette.org/twig2latte/]. You can download the tool from [GitHub|https://github.com/nette/latte-tools] or install it using Composer: @@ -77,5 +77,3 @@ After converting to Latte, we get this template: ``` - -{{leftbar: /@left-menu}} diff --git a/latte/en/cookbook/passing-variables.texy b/latte/en/cookbook/passing-variables.texy index 99a15c5596..6a77238810 100644 --- a/latte/en/cookbook/passing-variables.texy +++ b/latte/en/cookbook/passing-variables.texy @@ -156,6 +156,3 @@ The `{sandbox}` tag isolates the template for safe processing. Variables are pas ```latte {sandbox 'secure.latte', data: $secureData} ``` - - -{{leftbar: /@left-menu}} diff --git a/latte/en/cookbook/slim-framework.texy b/latte/en/cookbook/slim-framework.texy index 5621e0d012..542b82dc2c 100644 --- a/latte/en/cookbook/slim-framework.texy +++ b/latte/en/cookbook/slim-framework.texy @@ -155,4 +155,3 @@ Three ``` {{priority: -1}} -{{leftbar: /@left-menu}} diff --git a/latte/en/custom-filters.texy b/latte/en/custom-filters.texy index ee38269043..db6d77bf8d 100644 --- a/latte/en/custom-filters.texy +++ b/latte/en/custom-filters.texy @@ -84,7 +84,7 @@ Registration via Extension For better organization, especially when creating reusable sets of filters or sharing them as packages, the recommended way is to register them within a [Latte Extension |extending-latte#Latte Extension]: ```php -namespace App\Latte; +namespace App\Templating; use Latte\Extension; @@ -111,36 +111,12 @@ class MyLatteExtension extends Extension // Registration $latte = new Latte\Engine; -$latte->addExtension(new App\Latte\MyLatteExtension); +$latte->addExtension(new MyLatteExtension); ``` This approach keeps your filter logic encapsulated and makes registration straightforward. -Using a Filter Loader ---------------------- - -Latte allows registering a filter loader via `addFilterLoader()`. This is a single callable that Latte asks for any unknown filter name during compilation. The loader returns the filter's PHP callable or `null`. - -```php -$latte = new Latte\Engine; - -// Loader might dynamically create/fetch filter callables -$latte->addFilterLoader(function (string $name): ?callable { - if ($name === 'myLazyFilter') { - // Imagine expensive initialization here... - $service = get_some_expensive_service(); - return fn($value) => $service->process($value); - } - return null; -}); -``` - -This method was primarily intended for lazy loading filters with very **expensive initialization**. However, modern dependency injection practices usually handle lazy services more effectively. - -Filter loaders add complexity and are generally discouraged in favor of direct registration via `addFilter()` or within an Extension using `getFilters()`. Use loaders only if you have a strong, specific reason related to performance bottlenecks in filter initialization that cannot be addressed otherwise. - - Filters Using a Class with Attributes .{toc: Filters Using the Class} --------------------------------------------------------------------- diff --git a/latte/en/custom-functions.texy b/latte/en/custom-functions.texy index 4c4a4d423d..eeef7d8008 100644 --- a/latte/en/custom-functions.texy +++ b/latte/en/custom-functions.texy @@ -67,7 +67,7 @@ Registration via Extension For better organization and reusability, register functions within a [Latte Extension |extending-latte#Latte Extension]. This is the recommended approach for non-trivial applications or shared libraries. ```php -namespace App\Latte; +namespace App\Templating; use Latte\Extension; use Nette\Security\Authorizator; @@ -95,7 +95,7 @@ class MyLatteExtension extends Extension } // Registration (assuming $container holds the DIC) -$extension = $container->getByType(App\Latte\MyLatteExtension::class); +$extension = $container->getByType(MyLatteExtension::class); $latte = new Latte\Engine; $latte->addExtension($extension); ``` diff --git a/latte/en/custom-tags.texy b/latte/en/custom-tags.texy index ed99d6f014..b162bc8e10 100644 --- a/latte/en/custom-tags.texy +++ b/latte/en/custom-tags.texy @@ -117,7 +117,7 @@ Create a file (e.g., `DatetimeNode.php`) and define the class: ```php format()` method, which assembles the resulting PHP code string for the compiled template. The first argument, `'echo date('Y-m-d H:i:s') %line;'`, is the mask into which the subsequent parameters are substituted. The `%line` placeholder tells the `format()` method to take the second following argument, which is `$this->position`, and inserts a comment like `/* line 15 */` that links the generated PHP code back to the original template line, which is crucial for debugging. -Property `$this->position` is inherited from the base `Node` class, and is automatically set by Latte's parser. It holds a [api:Latte\Compiler\Position] object indicating where the tag was found in the source `.latte` file. +Property `$this->position` is inherited from the base `Node` class, and is automatically set by Latte's parser. It holds a [api:Latte\Compiler\Range] object (a subclass of `Position` extended with a `length` in bytes) indicating where the tag is located in the source `.latte` file. For paired tags the range spans from the opening to the closing tag, and `StatementNode` descendants additionally expose `$this->tagRanges` listing the `Range` of every constituent tag (opening, intermediate like `{else}`/`{case}`, and closing). The `getIterator()` method is vital for compiler passes. It must yield all child nodes, but our simple `DatetimeNode` currently has no arguments or content, thus no child nodes. However, the method must still exist and be a generator, i.e. the `yield` keyword must be somehow present in the method body. @@ -173,7 +173,7 @@ Finally, tell Latte about the new tag. Create an [Extension class |extending-lat ```php addExtension(new App\Latte\MyLatteExtension); +$latte->addExtension(new App\Templating\MyLatteExtension); ``` Create template: @@ -255,7 +255,7 @@ With that understanding, let's modify the `create()` method in `DatetimeNode` to ```php addExtension(new App\Latte\MyLatteExtension($isDev)); +$latte->addExtension(new MyLatteExtension($isDev)); ``` And use it in a template: @@ -555,7 +555,7 @@ Let's modify `DebugNode::create()` to expect `{else}`: ```php Delete ``` @@ -1003,8 +1003,8 @@ We've frequently used `PrintContext::format()` to generate PHP code in the `prin - **`%args`**: Argument must be an `Expression\ArrayNode`. It prints the array items formatted as arguments for a function or method call (comma-separated, handling named arguments if present). - `$argsNode = new ArrayNode([...]);` - `$context->format('myFunc(%args);', $argsNode)` -> `myFunc(1, name: 'Joe');` -- **`%line`**: Argument must be a `Position` object (usually `$this->position`). It inserts a PHP comment `/* line X */` indicating the source line number. - - `$context->format('echo "Hi" %line;', $this->position)` -> `echo "Hi" /* line 42 */;` +- **`%line`**: Argument must be a `Position` (or `Range`) object (usually `$this->position`). It inserts a PHP comment `/* line X */` indicating the source line number. + - `$context->format('echo "Hi" %line;', $this->position)` -> `echo "Hi" /* line 42:1 */;` - **`%escape(...)`**: It generates PHP code that, *at runtime*, will escape the inner expression using the current context-aware escaping rules. - `$context->format('echo %escape(%node);', $variableNode)` - **`%modify(...)`**: Argument must be a `ModifierNode`. It generates PHP code that applies the filters specified in the `ModifierNode` to the inner content, including context-aware escaping if not disabled by `|noescape`. @@ -1023,7 +1023,7 @@ While `parseExpression()`, `parseArguments()`, etc., cover many cases, sometimes ```php setTempDirectory('/path/to/tempdir'); +$latte->setCacheDirectory('/path/to/tempdir'); $params = [ /* template variables */ ]; // or $params = new TemplateParameters(/* ... */); @@ -57,6 +58,20 @@ $latte->setAutoRefresh(false); When deployed on a production server, the initial cache generation, especially for larger applications, can understandably take a while. Latte has built-in prevention against "cache stampede":https://en.wikipedia.org/wiki/Cache_stampede. This is a situation where server receives a large number of concurrent requests and because Latte's cache does not yet exist, they would all generate it at the same time. Which spikes CPU. Latte is smart, and when there are multiple concurrent requests, only the first thread generates the cache, the others wait and then use it. +Ways to Extend Latte +==================== + +Latte can be customized in several ways, from simple helpers to entirely new language constructs. The page [extending Latte |extending-latte] covers them in detail; here is a quick overview: + +- **[Custom Filters|custom-filters]:** for formatting or transforming data in the template output (e.g., `{$var|myFilter}`). +- **[Custom Functions|custom-functions]:** for custom logic you call within template expressions (e.g., `{myFunction($arg)}`). +- **[Custom Tags|custom-tags]:** for entirely new language constructs (`{mytag}...{/mytag}` or `n:mytag`). +- **[Compiler Passes|compiler-passes]:** functions that modify the template's AST between parsing and PHP code generation (for example, optimizations or security checks). +- **[Custom Loaders|loaders]:** for changing how Latte locates and loads template files. + +If you want to reuse your extensions across projects or share them with others, bundle them into a [Latte Extension |extending-latte#Latte Extension] class. + + Parameters as a Class ===================== @@ -183,16 +198,101 @@ In strict parsing mode, Latte checks for missing closing HTML tags and also disa ```php $latte = new Latte\Engine; -$latte->setStrictParsing(); +$latte->setFeature(Latte\Feature::StrictParsing); ``` To generate templates with the `declare(strict_types=1)` header, do the following: ```php $latte = new Latte\Engine; -$latte->setStrictTypes(); +$latte->setFeature(Latte\Feature::StrictTypes); +``` + +.[note] +Since Latte 3.1, strict types are enabled by default. You can disable them with `$latte->setFeature(Latte\Feature::StrictTypes, false)`. + + +Migration Warnings .{data-version:3.1} +====================================== + +Latte 3.1 changes the behavior of some [HTML attributes|html-attributes]. For example, `null` values now drop the attribute instead of printing an empty string. To easily find places where this change affects your templates, you can enable migration warnings: + +```php +$latte->setFeature(Latte\Feature::MigrationWarnings); +``` + +When enabled, Latte checks rendered attributes and triggers a user warning (`E_USER_WARNING`) if the output differs from what Latte 3.0 would have produced. When you encounter a warning, apply one of the solutions: + +1. If the new output is correct for your use case (e.g., you prefer the attribute to disappear when `null`), suppress the warning by adding the `|accept` filter +2. If you want the attribute to be rendered as empty (e.g. `title=""`) instead of being dropped when the variable is `null`, provide an empty string as a fallback: `title={$val ?? ''}` +3. If you strictly require the old behavior (e.g., printing `"1"` for `true` instead of `"true"`), explicitly cast the value to a string: `data-foo={(string) $val}` + +Once all warnings are resolved, disable migration warnings and **remove all** `|accept` filters from your templates, as they are no longer needed. + + +Scoped Loop Variables .{data-version:3.1.3} +=========================================== + +By default, variables defined in a `{foreach}` loop (like `$key` and `$value`) remain accessible after the loop ends – just like in PHP itself. This can lead to unintended variable overwrites when a loop variable has the same name as an existing template variable. + +The `ScopedLoopVariables` feature limits the scope of loop variables to the loop body. After the loop ends, the original variable value is restored (if it existed before), or the variable is unset: + +```php +$latte = new Latte\Engine; +$latte->setFeature(Latte\Feature::ScopedLoopVariables); +``` + +Example of the difference: + +```latte +{var $item = 'original'} +{foreach [1, 2] as $item}{$item}, {/foreach} +{$item} +``` + +Without `ScopedLoopVariables`: outputs `1, 2, 2` (variable is overwritten) +With `ScopedLoopVariables`: outputs `1, 2, original` (variable is restored) + +This also works with destructuring syntax, e.g. `{foreach $array as [$a, $b]}`. + +.[note] +Loop variables using references (`{foreach $array as &$value}`) or property assignments (`{foreach $array as $obj->prop}`) are not scoped, as this would break their intended purpose. + + +Automatic Dedentation .{toc: Dedent}{data-version:3.1.3} +======================================================== + +When using paired tags like `{if}`, `{foreach}`, or `{block}`, you often indent the nested content for readability. However, this indentation is included in the generated output by default. The `Dedent` feature automatically removes it, so the output stays clean regardless of how deeply you nest your Latte tags: + +```php +$latte = new Latte\Engine; +$latte->setFeature(Latte\Feature::Dedent); +``` + +Example: + +```latte +{if true} + Hello + World +{/if} +``` + +Without `Dedent`, the output would include the indentation (`\tHello\n\tWorld\n`). With `Dedent`, the indentation is stripped and the output is `Hello\nWorld\n`. + +Deeper indentation within a block is preserved relative to the base indentation: + +```latte +{if true} + Hello + Indented +{/if} ``` +Output: `Hello\n\tIndented\n`. + +Indentation within a block must be consistent (either tabs or spaces). If they are mixed, Latte throws an `Inconsistent indentation` exception. + Translation in Templates .{toc: TranslatorExtension} ==================================================== @@ -266,7 +366,9 @@ Since Latte compiles templates into readable PHP code, you can conveniently step Linter: Validating the Template Syntax .{toc: Linter} ===================================================== -The Linter tool will help you go through all templates and check for syntax errors. It is launched from the console: +The **Linter** tool is used to validate all templates. Its purpose is to scan the specified files and ensure that they contain no syntax errors and no references to non-existent tags, filters, functions, classes, or similar constructs. + +The Linter is executed from the command line: ```shell vendor/bin/latte-lint @@ -274,7 +376,7 @@ vendor/bin/latte-lint Use the `--strict` parameter to activate [#strict mode]. -If you use custom tags, also create your customized Linter, e.g. `custom-latte-lint`: +If you use custom tags, filters, or other Latte extensions, you need to create your own variant of the Linter, for example `custom-latte-lint`. In this script, you register all required extensions before the actual template validation takes place: ```php #!/usr/bin/env php @@ -302,6 +404,8 @@ $latte = new Latte\Engine; $linter = new Latte\Tools\Linter(engine: $latte); ``` +The resulting customized linter can then be used in the same way as the standard tool, but with full knowledge of all your custom extensions. + Loading Templates from a String =============================== diff --git a/latte/en/extending-latte.texy b/latte/en/extending-latte.texy index 9f63a3a280..22499f514a 100644 --- a/latte/en/extending-latte.texy +++ b/latte/en/extending-latte.texy @@ -44,13 +44,6 @@ $latte->addFilter('truncate', $myTruncate); // Template usage: {$text|truncate} or {$text|truncate:100} ``` -You can also register a **Filter Loader**, a function that dynamically provides filter callables based on the requested name: - -```php -$latte->addFilterLoader(fn(string $name) => /* return callable or null */); -``` - - Use `addFunction()` to register a function usable within template expressions. ```php diff --git a/latte/en/filters.texy b/latte/en/filters.texy index ca86861d1a..813daf354d 100644 --- a/latte/en/filters.texy +++ b/latte/en/filters.texy @@ -10,6 +10,9 @@ In templates, we can use functions that help modify or reformat data into its fi | `breakLines` | [Inserts HTML line breaks before all newlines |#breakLines] | `bytes` | [formats size in bytes |#bytes] | `clamp` | [clamps a value to the given range |#clamp] +| `column` | [extracts a single column from an array |#column] +| `commas` | [joins an array with commas |#commas] +| `limit` | [limits the length of an array, string, or iterator |#limit] | `dataStream` | [Data URI protocol conversion |#dataStream] | `date` | [formats the date and time |#date] | `explode` | [splits a string into an array by a delimiter |#explode] @@ -44,6 +47,7 @@ In templates, we can use functions that help modify or reformat data into its fi .[table-latte-filters] |## Letter Casing | `capitalize` | [lowercase, first letter of each word uppercase |#capitalize] +| `firstLower` | [converts the first letter to lower case |#firstLower] | `firstUpper` | [converts the first letter to uppercase |#firstUpper] | `lower` | [converts to lowercase |#lower] | `upper` | [converts to uppercase |#upper] @@ -54,6 +58,11 @@ In templates, we can use functions that help modify or reformat data into its fi | `floor` | [rounds a number down to a given precision |#floor] | `round` | [rounds a number to a given precision |#round] +.[table-latte-filters] +|## HTML Attributes +| `accept` | [accepts the new behavior of smart attributes |#accept] +| `toggle` | [toggles the presence of an HTML attribute |#toggle] + .[table-latte-filters] |## Escaping | `escapeUrl` | [escapes a parameter in a URL |#escapeUrl] @@ -116,10 +125,31 @@ It is then called in the template like this: ``` +Nullsafe Filters .{data-version:3.1} +------------------------------------ + +Any filter can be made nullsafe by using `?|` instead of `|`. If the value is `null`, the filter is not executed and `null` is returned. Subsequent filters in the chain are also skipped. + +This is useful in combination with HTML attributes, which are omitted if the value is `null`. + +```latte +
+{* If $title is null:
*} +{* If $title is 'hello':
*} +``` + + Filters ======= +accept .[filter]{data-version:3.1} +---------------------------------- +The filter is used during [migration from Latte 3.0|cookbook/migration-from-latte-30] to acknowledge that you've reviewed the attribute behavior change and accept it. It does not modify the value. + +This is a temporary tool. Once the migration is complete and migration warnings are disabled, you should remove this filter from your templates. + + batch(int $length, mixed $item): array .[filter] ------------------------------------------------ A filter that simplifies listing linear data in a table format. It returns an array of arrays with the specified number of items. If you provide a second parameter, it will be used to fill in missing items in the last row. @@ -198,7 +228,7 @@ Words will start with uppercase letters, all remaining characters will be lowerc {='i like LATTE'|capitalize} {* outputs 'I Like Latte' *} ``` -See also [#firstUpper], [#lower], [#upper]. +See also [#firstLower], [#firstUpper], [#lower], [#upper]. checkUrl .[filter] @@ -232,6 +262,50 @@ Clamps a value to the given inclusive range of min and max. Also exists as a [function |functions#clamp]. +column(string|int|null $columnKey, string|int|null $indexKey=null) .[filter]{data-version:3.1.3} +------------------------------------------------------------------------------------------------ +Returns the values of a single column `$columnKey` from a multidimensional array as a new array. Can also be used on arrays of objects to extract property values. + +```latte +{var $users = [ + [id: 30, name: 'John', age: 30], + [id: 32, name: 'Jane', age: 25], + [id: 33, age: 35], +]} + +{$users|column: 'name'} +{* returns ['John', 'Jane'] *} + +{$users|column: 'name', 'id'} +{* returns [30 => 'John', 32 => 'Jane'] *} +``` + +If you pass `null` as the column key, it will reindex the array according to `$indexKey`. + + +commas(?string $lastGlue=null) .[filter]{data-version:3.1.3} +------------------------------------------------------------ +Joins array elements with a comma and space (`', '`). A convenient shortcut for listing items in a human-readable format. + +```latte +{var $items = ['apples', 'oranges', 'bananas']} +{$items|commas} +{* outputs 'apples, oranges, bananas' *} +``` + +You can also provide a custom separator for the last pair of items: + +```latte +{$items|commas: ' and '} +{* outputs 'apples, oranges and bananas' *} + +{=['PHP', 'JavaScript', 'Python']|commas: ', or '} +{* outputs 'PHP, JavaScript, or Python' *} +``` + +See also [#implode]. + + dataStream(string $mimetype='detect') .[filter] ----------------------------------------------- Converts content to the data URI scheme. This allows embedding images into HTML or CSS without needing to link external files. @@ -324,6 +398,17 @@ Rounds a number down to the given precision. See also [#ceil], [#round]. +firstLower .[filter]{data-version:3.0.22} +----------------------------------------- +Converts the first letter to lower case. Requires PHP extension `mbstring`. + +```latte +{='The Latte'|firstLower} {* vypíše 'the Latte' *} +``` + +See also [#capitalize], [#firstUpper], [#lower], [#upper]. + + firstUpper .[filter] -------------------- Converts the first letter to uppercase. Requires the `mbstring` PHP extension. @@ -332,7 +417,7 @@ Converts the first letter to uppercase. Requires the `mbstring` PHP extension. {='the latte'|firstUpper} {* outputs 'The latte' *} ``` -See also [#capitalize], [#lower], [#upper]. +See also [#capitalize], [#firstLower], [#lower], [#upper]. group(string|int|\Closure $by): array .[filter]{data-version:3.0.16} @@ -369,6 +454,8 @@ You can also use the alias `join`: {=[1, 2, 3]|join} {* outputs '123' *} ``` +See also [#commas], [#explode]. + indent(int $level=1, string $char="\t") .[filter] ------------------------------------------------- @@ -490,7 +577,7 @@ Converts a string to lowercase. Requires the `mbstring` PHP extension. {='LATTE'|lower} {* outputs 'latte' *} ``` -See also [#capitalize], [#firstUpper], [#upper]. +See also [#capitalize], [#firstLower], [#firstUpper], [#upper]. nocheck .[filter] @@ -599,19 +686,21 @@ Remember that the actual appearance of numbers may vary depending on the country padLeft(int $length, string $pad=' ') .[filter] ----------------------------------------------- -Pads a string to a certain length with another string from the left. +Pads a string or number to a certain length with another string from the left. ```latte {='hello'|padLeft: 10, '123'} {* outputs '12312hello' *} +{=123|padLeft: 5, '0'} {* outputs '00123' *} ``` padRight(int $length, string $pad=' ') .[filter] ------------------------------------------------ -Pads a string to a certain length with another string from the right. +Pads a string or number to a certain length with another string from the right. ```latte {='hello'|padRight: 10, '123'} {* outputs 'hello12312' *} +{=123|padRight: 5, '0'} {* outputs '12300' *} ``` @@ -709,14 +798,14 @@ See also [#ceil], [#floor]. slice(int $start, ?int $length=null, bool $preserveKeys=false) .[filter] ------------------------------------------------------------------------ -Extracts a slice of an array or a string. +Extracts a slice of an array, string, or iterator. ```latte {='hello'|slice: 1, 2} {* outputs 'el' *} {=['a', 'b', 'c']|slice: 1, 2} {* outputs ['b', 'c'] *} ``` -The filter works like the PHP function `array_slice` for arrays or `mb_substr` for strings, with a fallback to the `iconv_substr` function in UTF‑8 mode. +The filter works like the PHP function `array_slice` for arrays or `mb_substr` for strings. For iterators, it returns a generator – elements are consumed from the source one by one and reading stops once the limit is reached. The entire iterator is never loaded into memory. If `start` is non-negative, the sequence will start at that offset from the beginning of the array/string. If `start` is negative, the sequence will start that far from the end. @@ -724,6 +813,21 @@ If `length` is given and is positive, then the sequence will have up to that man By default, the filter reorders and resets the integer array keys. This behavior can be changed by setting `preserveKeys` to true. String keys are always preserved, regardless of this parameter. +See also [#limit]. + + +limit(int $length) .[filter]{data-version:3.1.3} +------------------------------------------------ +Limits the length of an array, string, or iterator. For arrays and iterators, keys are preserved. For strings, it respects UTF-8. + +```latte +{foreach ($items|limit: 5) as $item} + ... +{/foreach} + +{$text|limit: 100} +``` + sort(?Closure $comparison, string|int|\Closure|null $by=null, string|int|\Closure|bool $byKey=false) .[filter] -------------------------------------------------------------------------------------------------------------- @@ -815,6 +919,21 @@ Extracts a portion of a string. This filter has been replaced by the [#slice] fi ``` +toggle .[filter]{data-version:3.1} +---------------------------------- +The `toggle` filter controls the presence of an attribute based on a boolean value. If the value is truthy, the attribute is present; if falsy, the attribute is omitted entirely: + +```latte +
+{* If $isGrid is truthy:
*} +{* If $isGrid is falsy:
*} +``` + +This filter is useful for custom attributes or JavaScript library attributes that require presence/absence control similar to HTML boolean attributes. + +The filter can only be used within HTML attributes. + + translate(...$args) .[filter] ----------------------------- Translates expressions into other languages. To make the filter available, you need to [set up the translator |develop#TranslatorExtension]. You can also use the [tags for translation |tags#Translation]. @@ -855,7 +974,7 @@ Converts a string to uppercase. Requires the `mbstring` PHP extension. {='latte'|upper} {* outputs 'LATTE' *} ``` -See also [#capitalize], [#firstUpper], [#lower]. +See also [#capitalize], [#firstLower], [#firstUpper], [#lower]. webalize .[filter] diff --git a/latte/en/functions.texy b/latte/en/functions.texy index 61edd5c5ad..f172c26df8 100644 --- a/latte/en/functions.texy +++ b/latte/en/functions.texy @@ -11,6 +11,7 @@ In addition to common PHP functions, you can also use these functions in templat | `first` | [returns the first element of an array or character of a string |#first] | `group` | [groups data according to various criteria |#group] | `hasBlock` | [detects the existence of a block |#hasBlock] +| `hasTemplate`| [detects the existence of a template |#hasTemplate] | `last` | [returns the last element of an array or character of a string |#last] | `odd` | [checks if the given number is odd |#odd] | `slice` | [extracts a slice of an array or a string |#slice] @@ -117,6 +118,15 @@ Checks if a block of the specified name exists: See also [block existence check |template-inheritance#Checking Block Existence]. +hasTemplate(string $name): bool .[method]{data-version:3.0.22} +-------------------------------------------------------------- +Determine if a template of the specified name exists: + +```latte +{if hasTemplate('foo.latte')} ... {/if} +``` + + last(string|array $value): mixed .[method] ------------------------------------------ Returns the last element of an array or the last character of a string: diff --git a/latte/en/html-attributes.texy b/latte/en/html-attributes.texy new file mode 100644 index 0000000000..1107579e99 --- /dev/null +++ b/latte/en/html-attributes.texy @@ -0,0 +1,151 @@ +Smart HTML Attributes +********************* + +.[perex] +Latte 3.1 comes with a set of improvements that focuses on one of the most common activities in templates – printing HTML attributes. It brings more convenience, flexibility and security. + + +Boolean Attributes +================== + +HTML uses special attributes like `checked`, `disabled`, `selected`, or `hidden`, where the specific value is irrelevant—only their presence matters. They act as simple flags. + +Latte handles them automatically. You can pass any expression to the attribute. If it is truthy, the attribute is rendered. If it is falsey (e.g. `false`, `null`, `0`, or an empty string), the attribute is completely omitted. + +This means you can say goodbye to cumbersome macro conditions or `n:attr` and simply use: + +```latte + +``` + +If `$isDisabled` is `false` and `$isReadOnly` is `true`, it renders: + +```latte + +``` + +If you need this toggling behavior for standard attributes that don't have this automatic handling (like `data-` or `aria-` attributes), use the [toggle |filters#toggle] filter. + + +Null Values +=========== + +This is one of the most pleasant changes. Previously, if a variable was `null`, it printed as an empty string `""`. This often led to empty attributes in HTML like `class=""` or `title=""`. + +In Latte 3.1, a new universal rule applies: **A value of `null` means the attribute does not exist.** + +```latte +
+``` + +If `$title` is `null`, the output is `
`. If it contains a string, e.g. "Hello", the output is `
`. Thanks to this, you don't have to wrap attributes in conditions. + +If you use filters, keep in mind that they usually convert `null` to a string (e.g. empty string). To prevent this, use the [nullsafe filter |filters#Nullsafe Filters] `?|`: + +```latte +
+``` + + +Classes +======= + +You can pass an array to the `class` attribute. This is perfect for conditional classes: if the array is associative, the keys are used as class names and the values as conditions. The class is rendered only if the condition is true. + +```latte + +``` + +If `$isActive` is true, it renders: + +```latte + +``` + +This behavior is not limited to `class`. It works for any HTML attribute that expects a space-separated list of values, such as `itemprop`, `rel`, `sandbox`, etc. + +```latte + $isExternal]}>link +``` + + +Styles +====== + +The `style` attribute also supports arrays. It is especially useful for conditional styles. If an array item contains a key (CSS property) and a value, the property is rendered only if the value is not `null`. + +```latte +
lightblue, + display => $isVisible ? block : null, + font-size => '16px', +]}>
+``` + +If `$isVisible` is false, it renders: + +```latte +
+``` + + +Data Attributes +=============== + +Often we need to pass configuration for JavaScript into HTML. Previously this was done via `json_encode`. Now you can simply pass an array or stdClass object to a `data-` attribute and Latte will serialize it to JSON: + +```latte +
+``` + +Outputs: + +```latte +
+``` + +Also, `true` and `false` are rendered as strings `"true"` and `"false"` (i.e. valid JSON). + + +Aria Attributes +=============== + +The WAI-ARIA specification requires text values `"true"` and `"false"` for boolean values. Latte handles this automatically for `aria-` attributes: + +```latte + +``` + +Outputs: + +```latte + +``` + + +Type Checking +============= + +Have you ever seen `` in your generated HTML? It's a classic bug that often goes unnoticed. Latte introduces strict type checking for HTML attributes to make your templates more resilient against such oversight. + +Latte knows which attributes are which and what values they expect: + +- **Standard attributes** (like `href`, `id`, `value`, `placeholder`...) expect a value that can be rendered as text. This includes strings, numbers, or stringable objects. `null` is also accepted (it drops the attribute). However, if you accidentally pass an array, boolean or a generic object, Latte triggers a warning and intelligently ignores the invalid value. +- **Boolean attributes** (like `checked`, `disabled`...) accept any type, as their presence is determined by truthy/falsey logic. +- **Smart attributes** (like `class`, `style`, `data-`...) specifically handle arrays as valid inputs. + +This check ensures that your application doesn't produce unexpected HTML. + + +Migration from Latte 3.0 +======================== + +Since the behavior of `null` (it used to print `""`, now it drops the attribute) and `data-` attributes (booleans used to print `"1"`/`""`, now `"true"`/`"false"`) has changed, you might need to update your templates. + +For a smooth transition, Latte provides a migration mode that highlights differences. Read the detailed guide [Migration from Latte 3.0 to 3.1|cookbook/migration-from-latte-30]. + +[* html-attributes.webp *] diff --git a/latte/en/loaders.texy b/latte/en/loaders.texy index cb5a28f9ce..6d76066022 100644 --- a/latte/en/loaders.texy +++ b/latte/en/loaders.texy @@ -105,7 +105,7 @@ getContent(string $name): string .[method] ------------------------------------------ This is the core method of the loader. Its task is to retrieve and return the full source code of the template identified by `$name` (as passed to the `$latte->render()` method or returned by the [#getReferredName()] method). -If the template cannot be found or accessed, this method **must throw a `Latte\RuntimeException`**. +If the template cannot be found or accessed, this method **must throw an `Latte\TemplateNotFoundException`**. ```php public function getContent(string $name): string @@ -169,7 +169,7 @@ class DatabaseLoader implements Latte\Loader $stmt->execute([$name]); $content = $stmt->fetchColumn(); if ($content === false) { - throw new Latte\RuntimeException("Template '$name' not found in database."); +throw new Latte\TemplateNotFoundException("Template '$name' not found in database."); } return $content; } diff --git a/latte/en/recipes.texy b/latte/en/recipes.texy index 37896b3ee5..7547e5b989 100644 --- a/latte/en/recipes.texy +++ b/latte/en/recipes.texy @@ -7,7 +7,7 @@ Editors and IDE Write templates in an editor or IDE that supports Latte. It will be much more pleasant. -- PhpStorm: install the [Latte plugin|https://plugins.jetbrains.com/plugin/7457-latte] in `Settings > Plugins > Marketplace` +- PhpStorm: install the [Latte plugin|https://plugins.jetbrains.com/plugin/24218-latte-support] in `Settings > Plugins > Marketplace` - VS Code: install [Nette Latte + Neon|https://marketplace.visualstudio.com/items?itemName=Kasik96.latte], [Nette Latte templates|https://marketplace.visualstudio.com/items?itemName=smuuf.latte-lang] or the latest [Nette for VS Code |https://marketplace.visualstudio.com/items?itemName=franken-ui.nette-for-vscode] plugin - NetBeans IDE: native support for Latte is included in the installation - Sublime Text 3: find and install the `Nette` package in Package Control and choose Latte in `View > Syntax` diff --git a/latte/en/safety-first.texy b/latte/en/safety-first.texy index 4e2c9480f4..004656ca94 100644 --- a/latte/en/safety-first.texy +++ b/latte/en/safety-first.texy @@ -33,7 +33,7 @@ echo '

Search results for ' . $search . '

'; An attacker can enter any string into the search box, and thus into the `$search` variable, including HTML code like ``. Since the output is not sanitized, it becomes part of the displayed page: -```html +```latte

Search results for

``` @@ -59,7 +59,7 @@ echo '' . $imageAlt . ''; An attacker simply needs to insert a cleverly crafted string `" onload="alert('Hacked!')` as the caption, and if the output is not sanitized, the resulting code will look like this: -```html +```latte ``` @@ -91,7 +91,7 @@ Context-Aware Escaping What exactly is meant by the word context? It's a location within the document with its own rules for handling the data being printed. It depends on the document type (HTML, XML, CSS, JavaScript, plain text, ...) and can differ in specific parts. For example, in an HTML document, there are many places (contexts) where very different rules apply. You might be surprised how many there are. Here are the first four: -```html +```latte

#text

@@ -108,7 +108,7 @@ It gets interesting inside HTML comments. Here, HTML entities are not used for e Contexts can also be layered, which occurs when we embed JavaScript or CSS into HTML. This can be done in two different ways, using an element or an attribute: -```html +```latte @@ -132,7 +132,7 @@ Let's take the string `Rock'n'Roll`. If you print it in HTML text, in this particular case, no replacement is needed because the string does not contain any characters with special meaning. The situation changes if you print it inside an HTML attribute enclosed in single quotes. In that case, you need to escape the quotes into HTML entities: -```html +```latte
``` @@ -152,13 +152,13 @@ alert('Rock\'n\'Roll'); If we insert this code into an HTML document using ` ``` However, if we wanted to insert it into an HTML attribute, we still need to escape the quotes into HTML entities: -```html +```latte
``` @@ -170,7 +170,7 @@ https://example.org/?a=Jazz&b=Rock%27n%27Roll And when we print this string in an attribute, we still apply escaping according to this context and replace `&` with `&`: -```html +```latte ``` @@ -314,7 +314,7 @@ Notice that there are no quotes around the attribute values. The coder might hav An attacker inserts a cleverly crafted string `foo onload=alert('Hacked!')` as the image caption. We already know that Twig cannot determine whether a variable is being printed in the HTML text flow, inside an attribute, an HTML comment, etc.; in short, it does not distinguish contexts. And it just mechanically converts the characters `< > & ' "` into HTML entities. So the resulting code will look like this: -```html +```latte foo ``` @@ -330,7 +330,7 @@ Now let's see how Latte handles the same template: Latte sees the template the same way you do. Unlike Twig, it understands HTML and knows that the variable is being printed as the value of an attribute that is not enclosed in quotes. Therefore, it adds them. When an attacker inserts the same caption, the resulting code will look like this: -```html +```latte foo onload=alert('Hacked!') ``` diff --git a/latte/en/syntax.texy b/latte/en/syntax.texy index a65b056772..aa7e274f5f 100644 --- a/latte/en/syntax.texy +++ b/latte/en/syntax.texy @@ -111,6 +111,34 @@ Which outputs, depending on the variable `$url`: However, n:attributes are not only a shortcut for pair tags, there are some pure n:attributes as well, for example the coder's best friend [n:class|tags#n:class] or the very handy [n:href |application:creating-links#In the Presenter Template]. +In addition to the syntax using quotes `
`, you can use alternative syntax with curly braces `
`. The main advantage is that you can freely use both single and double quotes inside `{...}`: + +```latte +
...
+``` + + +Smart HTML Attributes .{data-version:3.1} +========================================= + +Latte makes working with standard HTML attributes incredibly easy. It handles boolean attributes like `checked` for you, removes attributes containing `null`, and allows you to compose `class` and `style` values using arrays. It even automatically serializes data for `data-` attributes into JSON. + +```latte +{* null removes the attribute *} +
+ +{* boolean controls presence of boolean attributes *} + + +{* arrays work in class *} +
$isActive]}> + +{* arrays are JSON-encoded in data- attributes *} +
+``` + +Read more in the separate chapter [Smart HTML Attributes|html-attributes]. + Filters ======= @@ -148,10 +176,17 @@ On a block: ``` Or directly on a value (in combination with the [`{=expr}` |tags#Printing] tag): + ```latte

{=' Hello world '|trim}

``` +If the value can be `null` and you want to avoid applying the filter in that case, use the [nullsafe filter |filters#Nullsafe Filters] `?|`: + +```latte +

{$heading?|upper}

+``` + Dynamic HTML Tags .{data-version:3.0.9} ======================================= @@ -183,6 +218,41 @@ PHP comments work inside tags: ``` +Whitespace Control +================== + +Latte handles whitespace intelligently. You can freely indent your code for readability, and the output stays clean. When a tag appears alone on a line, the entire line (indentation and newline) is removed from the output: + +```latte +
    + {foreach $items as $item} +
  • {$item}
  • + {/foreach} +
+``` + +Outputs: + +```latte +
    +
  • foo
  • +
  • bar
  • +
+``` + +What if a tag isn't alone on a line, but appears alongside other content? The whitespace before the tag then belongs *inside* the tag: + +```latte +
+ {if $foo}hello{/if} +
+``` + +The indentation is effectively inside `{if}`: when `$foo` is false, nothing is output – not even the indentation or a blank line. When `$foo` is true, the output naturally includes the indentation. You simply write well-structured templates and the output is always clean. + +For even cleaner output, you can enable the [Dedent |develop#Dedent] feature, which also removes indentation caused by nesting within paired tags like `{if}` or `{foreach}`. + + Syntactic Sugar =============== @@ -204,7 +274,7 @@ Simple strings are those composed purely of letters, digits, underscores, hyphen Constants --------- -Since quotes can be omitted for simple strings, we recommend writing global constants with a leading slash to distinguish them: +Use the global namespace separator to distinguish global constants from simple strings: ```latte {if \PROJECT_ID === 1} ... {/if} @@ -265,8 +335,6 @@ A Window into History Over its history, Latte introduced several syntactic sugar features that appeared in PHP itself a few years later. For example, in Latte, it was possible to write arrays as `[1, 2, 3]` instead of `array(1, 2, 3)` or use the nullsafe operator `$obj?->foo` long before it was possible in PHP itself. Latte also introduced the array expansion operator `(expand) $arr`, which is equivalent to today's `...$arr` operator from PHP. -The undefined-safe operator `??->`, which is similar to the nullsafe operator `?->` but does not raise an error if the variable does not exist, was created for historical reasons, and today we recommend using the standard PHP operator `?->`. - PHP Limitations in Latte ======================== diff --git a/latte/en/tags.texy b/latte/en/tags.texy index d868f8db19..ffb90c69c1 100644 --- a/latte/en/tags.texy +++ b/latte/en/tags.texy @@ -16,7 +16,7 @@ An overview and description of all the tags available by default in the Latte te | `{ifset}` … `{elseifset}` … `{/ifset}` | [ifset condition |#ifset elseifset] | `{ifchanged}` … `{/ifchanged}` | [tests if a value has changed |#ifchanged] | `{switch}` `{case}` `{default}` `{/switch}` | [switch condition |#switch case default] -| `n:else` | [alternative content for conditions |#n:else] +| `n:else`, `n:elseif` | [alternative content for conditions |#n:else] .[table-latte-tags language-latte] |## Loops @@ -97,6 +97,7 @@ An overview and description of all the tags available by default in the Latte te | `n:href` | [link used in `
` HTML elements |application:creating-links#In the Presenter Template] | `{link}` | [prints a link |application:creating-links#In the Presenter Template] | `{plink}` | [prints a link to a presenter |application:creating-links#In the Presenter Template] +| `{linkBase}` | [changing link base |application:creating-links#Changing Link Base] | `{control}` | [renders a component |application:components#Rendering] | `{snippet}` … `{/snippet}` | [a template snippet that can be sent via AJAX |application:ajax#Snippets in Latte] | `{snippetArea}` | [snippet wrapper |application:ajax#Snippet Areas] @@ -136,7 +137,7 @@ You can write anything you know from PHP as an expression. You simply don't have ```latte -{='0' . ($num ?? $num * 3) . ', ' . PHP_VERSION} +{='0' . ($num ?? $num * 3) . ', ' . \PHP_VERSION} ``` Please don't look for any meaning in the previous example, but if you find one, let us know :-) @@ -251,18 +252,20 @@ Did you know you can add the `tag-` prefix to n:attributes? Then the condition w Awesome. -`n:else` .{data-version:3.0.11} -------------------------------- +`n:else` `n:elseif` .{toc: n:else}{data-version:3.0.11} +------------------------------------------------------- -If you write the `{if} ... {/if}` condition in the form of an [n:attribute |syntax#n:attributes], you have the option to specify an alternative branch using `n:else`: +If you write the `{if} ... {/if}` condition in the form of an [n:attribute |syntax#n:attributes], you have the option to specify alternative branches using `n:else` and `n:elseif` (since Latte 3.1): ```latte In stock {$count} items +Invalid count + not available ``` -The `n:else` attribute can also be used in conjunction with [`n:ifset` |#ifset elseifset], [`n:foreach` |#foreach], [`n:try` |#try], [#`n:ifcontent`], and [`n:ifchanged` |#ifchanged]. +The `n:else` attribute can also be used in conjunction with [`n:ifset` |#ifset elseifset], [`n:foreach` |#foreach], [`n:try` |#try], [`n:ifcontent`|#nifcontent], and [`n:ifchanged` |#ifchanged]. `{/if $cond}` @@ -629,6 +632,8 @@ The template name can be any PHP expression: {include $ajax ? 'ajax.latte' : 'not-ajax.latte'} ``` +If the template exists can be checked by the function [`hasTemplate()` |functions#hasTemplate]. + The included content can be modified using [filters |syntax#Filters]. The following example removes all HTML and adjusts the case: ```latte @@ -944,6 +949,9 @@ HTML Coder Helpers `n:class` --------- +.[note] +Since Latte 3.1, the standard HTML class attribute has gained the [same functionality |html-attributes#classes]. So you don't need to use n:class anymore + Thanks to `n:class`, it's very easy to generate the HTML `class` attribute exactly as needed. Example: I need the active element to have the class `active`: @@ -994,6 +1002,12 @@ Depending on the returned values, it prints, for example: ``` +Smart attribute features in Latte 3.1, such as dropping `null` values or passing arrays into `class` or `style`, also work within `n:attr`: + +```latte +
+``` + `n:tag` ------- diff --git a/latte/en/type-system.texy b/latte/en/type-system.texy index 8b7dfd642e..eac2758138 100644 --- a/latte/en/type-system.texy +++ b/latte/en/type-system.texy @@ -21,7 +21,7 @@ How to start using types? Create a template class, e.g., `CatalogTemplateParamet class CatalogTemplateParameters { public function __construct( - public string $langs, + public string $lang, /** @var ProductEntity[] */ public array $products, public Address $address, @@ -35,7 +35,7 @@ $latte->render('template.latte', new CatalogTemplateParameters( )); ``` -Then insert the `{templateType}` tag with the full class name (including the namespace) at the beginning of the template. This defines that the variables `$langs` and `$products` exist in the template, including their respective types. You can also specify the types of local variables using the [`{var}` |tags#var-default], `{varType}`, and [`{define}` |template-inheritance#Definitions] tags. +Then insert the `{templateType}` tag with the full class name (including the namespace) at the beginning of the template. This defines that the variables `$lang` and `$products` exist in the template, including their respective types. You can also specify the types of local variables using the [`{var}` |tags#var-default], `{varType}`, and [`{define}` |template-inheritance#Definitions] tags. From this point on, your IDE can correctly provide autocompletion. diff --git a/latte/es/@menu.texy b/latte/es/@menu.texy index ff48346f13..588b76348f 100644 --- a/latte/es/@menu.texy +++ b/latte/es/@menu.texy @@ -5,7 +5,7 @@
diff --git a/latte/es/@meta.texy b/latte/es/@meta.texy new file mode 100644 index 0000000000..ff4ce063ad --- /dev/null +++ b/latte/es/@meta.texy @@ -0,0 +1 @@ +{{sitename: Latte Documentación}} diff --git a/latte/es/cookbook/@home.texy b/latte/es/cookbook/@home.texy index 4f9621596d..c52c04ac36 100644 --- a/latte/es/cookbook/@home.texy +++ b/latte/es/cookbook/@home.texy @@ -11,5 +11,3 @@ Ejemplos de código y recetas para realizar tareas comunes con Latte. - [Migración desde PHP |migration-from-php] - [Migración desde Twig |migration-from-twig] - [Usar Latte con Slim 4 |slim-framework] - -{{leftbar: /@left-menu}} diff --git a/latte/es/cookbook/@meta.texy b/latte/es/cookbook/@meta.texy new file mode 100644 index 0000000000..03bf4d4c26 --- /dev/null +++ b/latte/es/cookbook/@meta.texy @@ -0,0 +1,2 @@ +{{sitename: Latte Documentación}} +{{leftbar: /@left-menu}} diff --git a/latte/es/cookbook/grouping.texy b/latte/es/cookbook/grouping.texy index e409b89715..d17635e747 100644 --- a/latte/es/cookbook/grouping.texy +++ b/latte/es/cookbook/grouping.texy @@ -249,6 +249,3 @@ Supongamos que en la tabla hay otra columna `subcategoryId` y, además de que ca {/foreach} ``` - - -{{leftbar: /@left-menu}} diff --git a/latte/es/cookbook/how-to-write-sql-queries-in-latte.texy b/latte/es/cookbook/how-to-write-sql-queries-in-latte.texy index 19de7a42e8..11140022f6 100644 --- a/latte/es/cookbook/how-to-write-sql-queries-in-latte.texy +++ b/latte/es/cookbook/how-to-write-sql-queries-in-latte.texy @@ -38,5 +38,3 @@ $result = $db->query($sql); ``` *El ejemplo proporcionado requiere Latte v3.0.5 o superior.* - -{{leftbar: /@left-menu}} diff --git a/latte/es/cookbook/migration-from-php.texy b/latte/es/cookbook/migration-from-php.texy index c6bbbd2855..6f3cd6e4ad 100644 --- a/latte/es/cookbook/migration-from-php.texy +++ b/latte/es/cookbook/migration-from-php.texy @@ -2,7 +2,7 @@ Migración de PHP a Latte ************************ .[perex] -¿Estás convirtiendo un proyecto antiguo escrito en PHP puro a Latte? Tenemos una herramienta para ti que facilitará la migración. [Pruébala en línea |https://php2latte.nette.org]. +¿Estás convirtiendo un proyecto antiguo escrito en PHP puro a Latte? Tenemos una herramienta para ti que facilitará la migración. [Pruébala en línea |https://fiddle.nette.org/php2latte/]. Puedes descargar la herramienta desde [GitHub|https://github.com/nette/latte-tools] o instalarla usando Composer: @@ -68,5 +68,3 @@ Genera esta plantilla Latte:
``` - -{{leftbar: /@left-menu}} diff --git a/latte/es/cookbook/migration-from-twig.texy b/latte/es/cookbook/migration-from-twig.texy index f1d768a662..443a6f381f 100644 --- a/latte/es/cookbook/migration-from-twig.texy +++ b/latte/es/cookbook/migration-from-twig.texy @@ -2,7 +2,7 @@ Migración de Twig a Latte ************************* .[perex] -¿Estás convirtiendo un proyecto escrito en Twig al más moderno Latte? Tenemos una herramienta para ti que facilitará la migración. [Pruébala en línea |https://twig2latte.nette.org]. +¿Estás convirtiendo un proyecto escrito en Twig al más moderno Latte? Tenemos una herramienta para ti que facilitará la migración. [Pruébala en línea |https://fiddle.nette.org/twig2latte/]. Puedes descargar la herramienta desde [GitHub|https://github.com/nette/latte-tools] o instalarla usando Composer: @@ -77,5 +77,3 @@ Después de la conversión a Latte, obtenemos esta plantilla: ``` - -{{leftbar: /@left-menu}} diff --git a/latte/es/cookbook/passing-variables.texy b/latte/es/cookbook/passing-variables.texy index 764c878f4a..21ed20c634 100644 --- a/latte/es/cookbook/passing-variables.texy +++ b/latte/es/cookbook/passing-variables.texy @@ -156,6 +156,3 @@ La etiqueta `{sandbox}` aísla la plantilla para un procesamiento seguro. Las va ```latte {sandbox 'secure.latte', data: $secureData} ``` - - -{{leftbar: /@left-menu}} diff --git a/latte/es/cookbook/slim-framework.texy b/latte/es/cookbook/slim-framework.texy index 86a7d7b278..7a2a59103b 100644 --- a/latte/es/cookbook/slim-framework.texy +++ b/latte/es/cookbook/slim-framework.texy @@ -155,4 +155,3 @@ Three ``` {{priority: -1}} -{{leftbar: /@left-menu}} diff --git a/latte/es/custom-tags.texy b/latte/es/custom-tags.texy index f32e309910..fbb0646b5b 100644 --- a/latte/es/custom-tags.texy +++ b/latte/es/custom-tags.texy @@ -923,7 +923,7 @@ Ahora puede usar `n:confirm` en enlaces, botones o elementos de formulario: HTML generado: -```html +```latte Eliminar ``` diff --git a/latte/es/safety-first.texy b/latte/es/safety-first.texy index 437dd39aac..6fe173ea9c 100644 --- a/latte/es/safety-first.texy +++ b/latte/es/safety-first.texy @@ -33,7 +33,7 @@ echo '

Resultados de la búsqueda para ' . $search . '

'; Un atacante puede escribir en el campo de búsqueda y, por extensión, en la variable `$search` cualquier cadena, incluido código HTML como ``. Dado que la salida no está saneada de ninguna manera, se convierte en parte de la página mostrada: -```html +```latte

Resultados de la búsqueda para

``` @@ -59,7 +59,7 @@ echo '' . $imageAlt . ''; Al atacante le basta con insertar como descripción una cadena hábilmente construida `" onload="alert('Hacked!')` y si la impresión no está saneada, el código resultante se verá así: -```html +```latte ``` @@ -91,7 +91,7 @@ Escape sensible al contexto ¿Qué se entiende exactamente por la palabra contexto? Es un lugar en el documento con sus propias reglas para el saneamiento de los datos impresos. Depende del tipo de documento (HTML, XML, CSS, JavaScript, texto plano, ...) y puede diferir en sus partes específicas. Por ejemplo, en un documento HTML hay muchos lugares (contextos) donde se aplican reglas muy diferentes. Quizás se sorprenda de cuántos hay. Aquí tenemos los primeros cuatro: -```html +```latte

#texto

@@ -108,7 +108,7 @@ Es interesante dentro de los comentarios HTML. Aquí, el escape no se realiza ut Los contextos también pueden anidarse, lo que ocurre cuando insertamos JavaScript o CSS en HTML. Esto se puede hacer de dos maneras diferentes, con un elemento y con un atributo: -```html +```latte @@ -132,7 +132,7 @@ Tomemos la cadena `Rock'n'Roll`. Si la imprime en texto HTML, en este caso particular no es necesario realizar ningún reemplazo, porque la cadena no contiene ningún carácter con significado especial. La situación cambia si la imprime dentro de un atributo HTML delimitado por comillas simples. En ese caso, es necesario escapar las comillas a entidades HTML: -```html +```latte
``` @@ -152,13 +152,13 @@ alert('Rock\'n\'Roll'); Si insertamos este código en un documento HTML usando ` ``` Sin embargo, si quisiéramos insertarlo en un atributo HTML, aún debemos escapar las comillas a entidades HTML: -```html +```latte
``` @@ -170,7 +170,7 @@ https://example.org/?a=Jazz&b=Rock%27n%27Roll Y cuando imprimimos esta cadena en un atributo, aún aplicamos el escape según este contexto y reemplazamos `&` por `&`: -```html +```latte ``` @@ -314,7 +314,7 @@ Observe que no hay comillas alrededor de los valores de los atributos. El codifi Un atacante inserta como descripción de la imagen una cadena hábilmente construida `foo onload=alert('Hacked!')`. Ya sabemos que Twig no puede saber si la variable se imprime en el flujo de texto HTML, dentro de un atributo, comentario HTML, etc., en resumen, no distingue contextos. Y solo convierte mecánicamente los caracteres `< > & ' "` en entidades HTML. Así que el código resultante se verá así: -```html +```latte foo ``` @@ -330,7 +330,7 @@ Ahora veamos cómo Latte maneja la misma plantilla: Latte ve la plantilla igual que usted. A diferencia de Twig, entiende HTML y sabe que la variable se imprime como el valor de un atributo que no está entre comillas. Por eso las añade. Cuando un atacante inserta la misma descripción, el código resultante se verá así: -```html +```latte foo onload=alert('Hacked!') ``` diff --git a/latte/es/type-system.texy b/latte/es/type-system.texy index b3b4097727..d1cacbcb12 100644 --- a/latte/es/type-system.texy +++ b/latte/es/type-system.texy @@ -21,7 +21,7 @@ Los tipos declarados son informativos y Latte no los verifica en este momento. class CatalogTemplateParameters { public function __construct( - public string $langs, + public string $lang, /** @var ProductEntity[] */ public array $products, public Address $address, @@ -35,7 +35,7 @@ $latte->render('template.latte', new CatalogTemplateParameters( )); ``` -Y luego, al principio de la plantilla, inserte la etiqueta `{templateType}` con el nombre completo de la clase (incluido el namespace). Esto define que en la plantilla existen las variables `$langs` y `$products` con sus tipos correspondientes. Puede indicar los tipos de las variables locales usando las etiquetas [`{var}` |tags#var default], `{varType}`, [`{define}` |template-inheritance#Definiciones define]. +Y luego, al principio de la plantilla, inserte la etiqueta `{templateType}` con el nombre completo de la clase (incluido el namespace). Esto define que en la plantilla existen las variables `$lang` y `$products` con sus tipos correspondientes. Puede indicar los tipos de las variables locales usando las etiquetas [`{var}` |tags#var default], `{varType}`, [`{define}` |template-inheritance#Definiciones define]. A partir de ese momento, su IDE puede sugerir correctamente. diff --git a/latte/files/html-attributes.webp b/latte/files/html-attributes.webp new file mode 100644 index 0000000000..56e729541b Binary files /dev/null and b/latte/files/html-attributes.webp differ diff --git a/latte/fr/@menu.texy b/latte/fr/@menu.texy index 1cb2c5d801..0a5e697225 100644 --- a/latte/fr/@menu.texy +++ b/latte/fr/@menu.texy @@ -5,8 +5,8 @@ diff --git a/latte/fr/@meta.texy b/latte/fr/@meta.texy new file mode 100644 index 0000000000..de304f749e --- /dev/null +++ b/latte/fr/@meta.texy @@ -0,0 +1 @@ +{{sitename: Documentation Latte}} diff --git a/latte/fr/cookbook/@home.texy b/latte/fr/cookbook/@home.texy index a77e52a5fd..e4e991619d 100644 --- a/latte/fr/cookbook/@home.texy +++ b/latte/fr/cookbook/@home.texy @@ -11,5 +11,3 @@ Exemples de code et recettes pour effectuer des tâches courantes à l'aide de L - [Migration depuis PHP |migration-from-php] - [Migration depuis Twig |migration-from-twig] - [Utilisation de Latte avec Slim 4 |slim-framework] - -{{leftbar: /@left-menu}} diff --git a/latte/fr/cookbook/@meta.texy b/latte/fr/cookbook/@meta.texy new file mode 100644 index 0000000000..8d7106bacb --- /dev/null +++ b/latte/fr/cookbook/@meta.texy @@ -0,0 +1,2 @@ +{{sitename: Documentation Latte}} +{{leftbar: /@left-menu}} diff --git a/latte/fr/cookbook/grouping.texy b/latte/fr/cookbook/grouping.texy index aa797bb8aa..f5a6d804a8 100644 --- a/latte/fr/cookbook/grouping.texy +++ b/latte/fr/cookbook/grouping.texy @@ -249,6 +249,3 @@ Supposons qu'il y ait une autre colonne `subcategoryId` dans la table et qu'en p {/foreach} ``` - - -{{leftbar: /@left-menu}} diff --git a/latte/fr/cookbook/how-to-write-sql-queries-in-latte.texy b/latte/fr/cookbook/how-to-write-sql-queries-in-latte.texy index cb72a69fce..42ec809f0a 100644 --- a/latte/fr/cookbook/how-to-write-sql-queries-in-latte.texy +++ b/latte/fr/cookbook/how-to-write-sql-queries-in-latte.texy @@ -38,5 +38,3 @@ $result = $db->query($sql); ``` *L'exemple donné nécessite Latte v3.0.5 ou supérieur.* - -{{leftbar: /@left-menu}} diff --git a/latte/fr/cookbook/migration-from-php.texy b/latte/fr/cookbook/migration-from-php.texy index afc182ca83..0e35a4fc88 100644 --- a/latte/fr/cookbook/migration-from-php.texy +++ b/latte/fr/cookbook/migration-from-php.texy @@ -2,7 +2,7 @@ Migration de PHP vers Latte *************************** .[perex] -Vous convertissez un ancien projet écrit en PHP pur vers Latte ? Nous avons un outil pour vous faciliter la migration. [Essayez-le en ligne |https://php2latte.nette.org]. +Vous convertissez un ancien projet écrit en PHP pur vers Latte ? Nous avons un outil pour vous faciliter la migration. [Essayez-le en ligne |https://fiddle.nette.org/php2latte/]. Vous pouvez télécharger l'outil depuis [GitHub |https://github.com/nette/latte-tools] ou l'installer via Composer : @@ -68,5 +68,3 @@ Il génère ce template :
``` - -{{leftbar: /@left-menu}} diff --git a/latte/fr/cookbook/migration-from-twig.texy b/latte/fr/cookbook/migration-from-twig.texy index 249b7677bc..551678e9ab 100644 --- a/latte/fr/cookbook/migration-from-twig.texy +++ b/latte/fr/cookbook/migration-from-twig.texy @@ -2,7 +2,7 @@ Migration de Twig vers Latte **************************** .[perex] -Vous convertissez un projet écrit en Twig vers le plus moderne Latte ? Nous avons un outil pour vous faciliter la migration. [Essayez-le en ligne |https://twig2latte.nette.org]. +Vous convertissez un projet écrit en Twig vers le plus moderne Latte ? Nous avons un outil pour vous faciliter la migration. [Essayez-le en ligne |https://fiddle.nette.org/twig2latte/]. Vous pouvez télécharger l'outil depuis [GitHub |https://github.com/nette/latte-tools] ou l'installer via Composer : @@ -77,5 +77,3 @@ Après conversion en Latte, nous obtenons ce template : ``` - -{{leftbar: /@left-menu}} diff --git a/latte/fr/cookbook/passing-variables.texy b/latte/fr/cookbook/passing-variables.texy index dcf75d7368..5aa0e33d3b 100644 --- a/latte/fr/cookbook/passing-variables.texy +++ b/latte/fr/cookbook/passing-variables.texy @@ -156,6 +156,3 @@ La balise `{sandbox}` isole le template pour un traitement sécurisé. Les varia ```latte {sandbox 'secure.latte', data: $secureData} ``` - - -{{leftbar: /@left-menu}} diff --git a/latte/fr/cookbook/slim-framework.texy b/latte/fr/cookbook/slim-framework.texy index 0d76ba7342..9006774afe 100644 --- a/latte/fr/cookbook/slim-framework.texy +++ b/latte/fr/cookbook/slim-framework.texy @@ -155,4 +155,3 @@ Three ``` {{priority: -1}} -{{leftbar: /@left-menu}} diff --git a/latte/fr/custom-tags.texy b/latte/fr/custom-tags.texy index 29c14a08a8..9983a44429 100644 --- a/latte/fr/custom-tags.texy +++ b/latte/fr/custom-tags.texy @@ -923,7 +923,7 @@ Vous pouvez maintenant utiliser `n:confirm` sur des liens, des boutons ou des é HTML généré : -```html +```latte Supprimer ``` diff --git a/latte/fr/safety-first.texy b/latte/fr/safety-first.texy index e4b3f5a93a..d9476e4305 100644 --- a/latte/fr/safety-first.texy +++ b/latte/fr/safety-first.texy @@ -33,7 +33,7 @@ echo '

Résultats de la recherche pour ' . $search . '

'; Un attaquant peut entrer dans le champ de recherche et donc dans la variable `$search` n'importe quelle chaîne, y compris du code HTML comme ``. Comme la sortie n'est pas traitée, elle devient partie intégrante de la page affichée : -```html +```latte

Résultats de la recherche pour

``` @@ -59,7 +59,7 @@ echo '' . $imageAlt . ''; Il suffit à l'attaquant d'insérer comme légende une chaîne habilement construite `" onload="alert('Piraté !')` et si l'affichage n'est pas traité, le code résultant ressemblera à ceci : -```html +```latte ``` @@ -91,7 +91,7 @@ Cependant, XSS ne concerne pas seulement l'affichage des données dans les templ Que signifie exactement le mot contexte ? C'est un endroit dans le document avec ses propres règles pour traiter les données affichées. Il dépend du type de document (HTML, XML, CSS, JavaScript, texte brut, ...) et peut varier dans ses parties spécifiques. Par exemple, dans un document HTML, il existe de nombreux endroits (contextes) où des règles très différentes s'appliquent. Vous serez peut-être surpris de leur nombre. Voici les quatre premiers : -```html +```latte

#texte

@@ -108,7 +108,7 @@ C'est intéressant à l'intérieur des commentaires HTML. Ici, l'échappement n' Les contextes peuvent également être imbriqués, ce qui se produit lorsque nous insérons du JavaScript ou du CSS dans du HTML. Cela peut être fait de deux manières différentes, par élément et par attribut : -```html +```latte @@ -132,7 +132,7 @@ Prenons la chaîne `Rock'n'Roll`. Si vous l'affichez dans du texte HTML, dans ce cas précis, il n'est pas nécessaire de faire de remplacements, car la chaîne ne contient aucun caractère ayant une signification spéciale. La situation change si vous l'affichez à l'intérieur d'un attribut HTML entouré de guillemets simples. Dans ce cas, il faut échapper les guillemets en entités HTML : -```html +```latte
``` @@ -152,13 +152,13 @@ alert('Rock\'n\'Roll'); Si nous insérons ce code dans un document HTML à l'aide de ` ``` Cependant, si nous voulions l'insérer dans un attribut HTML, nous devrions encore échapper les guillemets en entités HTML : -```html +```latte
``` @@ -170,7 +170,7 @@ https://example.org/?a=Jazz&b=Rock%27n%27Roll Et lorsque nous affichons cette chaîne dans un attribut, nous appliquons encore l'échappement selon ce contexte et remplaçons `&` par `&`: -```html +```latte ``` @@ -314,7 +314,7 @@ Notez qu'il n'y a pas de guillemets autour des valeurs des attributs. Le codeur L'attaquant insère comme légende de l'image une chaîne habilement construite `foo onload=alert('Piraté !')`. Nous savons déjà que Twig ne peut pas savoir si la variable est affichée dans le flux de texte HTML, à l'intérieur d'un attribut, d'un commentaire HTML, etc., bref, il ne distingue pas les contextes. Et il ne fait que convertir mécaniquement les caractères `< > & ' "` en entités HTML. Le code résultant ressemblera donc à ceci : -```html +```latte foo ``` @@ -330,7 +330,7 @@ Voyons maintenant comment Latte gère le même template : Latte voit le template de la même manière que vous. Contrairement à Twig, il comprend HTML et sait que la variable est affichée comme valeur d'un attribut qui n'est pas entre guillemets. C'est pourquoi il les ajoute. Lorsque l'attaquant insère la même légende, le code résultant ressemblera à ceci : -```html +```latte foo onload=alert('Piraté !') ``` diff --git a/latte/fr/type-system.texy b/latte/fr/type-system.texy index 8419906504..0cac1c1ac0 100644 --- a/latte/fr/type-system.texy +++ b/latte/fr/type-system.texy @@ -21,7 +21,7 @@ Comment commencer à utiliser les types ? Créez une classe de template, par exe class CatalogTemplateParameters { public function __construct( - public string $langs, + public string $lang, /** @var ProductEntity[] */ public array $products, public Address $address, @@ -35,7 +35,7 @@ $latte->render('template.latte', new CatalogTemplateParameters( )); ``` -Ensuite, au début du template, insérez la balise `{templateType}` avec le nom complet de la classe (y compris le namespace). Cela définit que les variables `$langs` et `$products` existent dans le template, y compris leurs types respectifs. Vous pouvez spécifier les types des variables locales à l'aide des balises [`{var}` |tags#var default], `{varType}`, [`{define}` |template-inheritance#Définitions]. +Ensuite, au début du template, insérez la balise `{templateType}` avec le nom complet de la classe (y compris le namespace). Cela définit que les variables `$lang` et `$products` existent dans le template, y compris leurs types respectifs. Vous pouvez spécifier les types des variables locales à l'aide des balises [`{var}` |tags#var default], `{varType}`, [`{define}` |template-inheritance#Définitions]. À partir de ce moment, l'IDE peut correctement vous faire des suggestions. diff --git a/latte/hu/@menu.texy b/latte/hu/@menu.texy index 0ed08fb67e..440653c9f5 100644 --- a/latte/hu/@menu.texy +++ b/latte/hu/@menu.texy @@ -5,7 +5,7 @@ diff --git a/latte/hu/@meta.texy b/latte/hu/@meta.texy new file mode 100644 index 0000000000..e9ee4e35c0 --- /dev/null +++ b/latte/hu/@meta.texy @@ -0,0 +1 @@ +{{sitename: Latte dokumentáció}} diff --git a/latte/hu/cookbook/@home.texy b/latte/hu/cookbook/@home.texy index 42af8d4207..b1351a25fb 100644 --- a/latte/hu/cookbook/@home.texy +++ b/latte/hu/cookbook/@home.texy @@ -11,5 +11,3 @@ Kódpéldák és receptek gyakori feladatok elvégzéséhez Latte segítségéve - [Migráció PHP-ból |migration-from-php] - [Migráció Twig-ből |migration-from-twig] - [Latte használata Slim 4-gyel |slim-framework] - -{{leftbar: /@left-menu}} diff --git a/latte/hu/cookbook/@meta.texy b/latte/hu/cookbook/@meta.texy new file mode 100644 index 0000000000..f7e3fec4be --- /dev/null +++ b/latte/hu/cookbook/@meta.texy @@ -0,0 +1,2 @@ +{{sitename: Latte dokumentáció}} +{{leftbar: /@left-menu}} diff --git a/latte/hu/cookbook/grouping.texy b/latte/hu/cookbook/grouping.texy index 717350d841..b74f61ca75 100644 --- a/latte/hu/cookbook/grouping.texy +++ b/latte/hu/cookbook/grouping.texy @@ -249,6 +249,3 @@ Tegyük fel, hogy a táblázatban van még egy `subcategoryId` oszlop, és amell {/foreach} ``` - - -{{leftbar: /@left-menu}} diff --git a/latte/hu/cookbook/how-to-write-sql-queries-in-latte.texy b/latte/hu/cookbook/how-to-write-sql-queries-in-latte.texy index 7bafc730d2..298a9b06a0 100644 --- a/latte/hu/cookbook/how-to-write-sql-queries-in-latte.texy +++ b/latte/hu/cookbook/how-to-write-sql-queries-in-latte.texy @@ -38,5 +38,3 @@ $result = $db->query($sql); ``` *A megadott példa Latte 3.0.5 vagy újabb verziót igényel.* - -{{leftbar: /@left-menu}} diff --git a/latte/hu/cookbook/migration-from-php.texy b/latte/hu/cookbook/migration-from-php.texy index 35df41e7eb..5b008b1c15 100644 --- a/latte/hu/cookbook/migration-from-php.texy +++ b/latte/hu/cookbook/migration-from-php.texy @@ -2,7 +2,7 @@ Migráció PHP-ból Latte-ba ************************* .[perex] -Átalakít egy régi, tiszta PHP-ban írt projektet Latte-ra? Van egy eszközünk, amely megkönnyíti a migrációt. [Próbálja ki online |https://php2latte.nette.org]. +Átalakít egy régi, tiszta PHP-ban írt projektet Latte-ra? Van egy eszközünk, amely megkönnyíti a migrációt. [Próbálja ki online |https://fiddle.nette.org/php2latte/]. Az eszközt letöltheti a [GitHubról|https://github.com/nette/latte-tools] vagy telepítheti a Composer segítségével: @@ -68,5 +68,3 @@ Ez a sablon generálódik:
``` - -{{leftbar: /@left-menu}} diff --git a/latte/hu/cookbook/migration-from-twig.texy b/latte/hu/cookbook/migration-from-twig.texy index 92b9c4c4a3..caed7d2013 100644 --- a/latte/hu/cookbook/migration-from-twig.texy +++ b/latte/hu/cookbook/migration-from-twig.texy @@ -2,7 +2,7 @@ Migráció Twig-ből Latte-ba ************************** .[perex] -Átalakít egy Twig-ben írt projektet a modernebb Latte-ra? Van egy eszközünk, amely megkönnyíti a migrációt. [Próbálja ki online |https://twig2latte.nette.org]. +Átalakít egy Twig-ben írt projektet a modernebb Latte-ra? Van egy eszközünk, amely megkönnyíti a migrációt. [Próbálja ki online |https://fiddle.nette.org/twig2latte/]. Az eszközt letöltheti a [GitHubról|https://github.com/nette/latte-tools] vagy telepítheti a Composer segítségével: @@ -77,5 +77,3 @@ A Latte-ba történő konverzió után ezt a sablont kapjuk: ``` - -{{leftbar: /@left-menu}} diff --git a/latte/hu/cookbook/passing-variables.texy b/latte/hu/cookbook/passing-variables.texy index cc2ea2efad..4106596008 100644 --- a/latte/hu/cookbook/passing-variables.texy +++ b/latte/hu/cookbook/passing-variables.texy @@ -156,6 +156,3 @@ A `{sandbox}` tag izolálja a sablont a biztonságos feldolgozáshoz. A változ ```latte {sandbox 'secure.latte', data: $secureData} ``` - - -{{leftbar: /@left-menu}} diff --git a/latte/hu/cookbook/slim-framework.texy b/latte/hu/cookbook/slim-framework.texy index c0069a87a2..309feb6a15 100644 --- a/latte/hu/cookbook/slim-framework.texy +++ b/latte/hu/cookbook/slim-framework.texy @@ -155,4 +155,3 @@ Three ``` {{priority: -1}} -{{leftbar: /@left-menu}} diff --git a/latte/hu/custom-tags.texy b/latte/hu/custom-tags.texy index f8e2946305..6b7f70dbe5 100644 --- a/latte/hu/custom-tags.texy +++ b/latte/hu/custom-tags.texy @@ -923,7 +923,7 @@ Most már használhatja az `n:confirm`-ot linkeken, gombokon vagy űrlap elemeke Generált HTML: -```html +```latte Törlés ``` diff --git a/latte/hu/safety-first.texy b/latte/hu/safety-first.texy index a07f648fe6..a1b2547fa0 100644 --- a/latte/hu/safety-first.texy +++ b/latte/hu/safety-first.texy @@ -33,7 +33,7 @@ echo '

Keresési eredmények erre: ' . $search . '

'; A támadó a keresőmezőbe és ezáltal a `$search` változóba bármilyen stringet beírhat, tehát HTML kódot is, mint ``. Mivel a kimenet nincs semmilyen módon kezelve, a megjelenített oldal részévé válik: -```html +```latte

Keresési eredmények erre:

``` @@ -59,7 +59,7 @@ echo '' . $imageAlt . ''; A támadónak elég leírásként egy ügyesen összeállított `" onload="alert('Hacked!')` stringet beilleszteni, és ha a kiírás nincs kezelve, az eredményül kapott kód így fog kinézni: -```html +```latte ``` @@ -91,7 +91,7 @@ Kontextusérzékeny escapelés Mit jelent pontosan a kontextus szó? Ez egy hely a dokumentumban, saját szabályokkal a kiírt adatok kezelésére. A dokumentum típusától (HTML, XML, CSS, JavaScript, plain text, ...) függ, és eltérhet annak konkrét részeiben. Például egy HTML dokumentumban számos ilyen hely (kontextus) van, ahol nagyon eltérő szabályok érvényesek. Talán meglepődik, mennyi van belőlük. Íme az első négy: -```html +```latte

#szöveg

@@ -108,7 +108,7 @@ Talán meglepő, de speciális szabályok érvényesek a ` @@ -108,7 +108,7 @@ Potresti essere sorpreso, ma regole speciali si applicano all'interno degli elem I contesti possono anche essere annidati, cosa che accade quando inseriamo JavaScript o CSS in HTML. Questo può essere fatto in due modi diversi, con un elemento e con un attributo: -```html +```latte @@ -132,7 +132,7 @@ Prendiamo la stringa `Rock'n'Roll`. Se la stampi nel testo HTML, proprio in questo caso non è necessario effettuare alcuna sostituzione, perché la stringa non contiene alcun carattere con significato speciale. La situazione cambia se la stampi all'interno di un attributo HTML racchiuso tra apici singoli. In tal caso, è necessario eseguire l'escaping degli apici in entità HTML: -```html +```latte
``` @@ -152,13 +152,13 @@ alert('Rock\'n\'Roll'); Se inseriamo questo codice nel documento HTML usando ` ``` Se però volessimo inserirlo in un attributo HTML, dobbiamo ancora eseguire l'escaping degli apici in entità HTML: -```html +```latte
``` @@ -170,7 +170,7 @@ https://example.org/?a=Jazz&b=Rock%27n%27Roll E quando stampiamo questa stringa in un attributo, applichiamo ancora l'escaping secondo questo contesto e sostituiamo `&` con `&`: -```html +```latte ``` @@ -314,7 +314,7 @@ Notate che non ci sono virgolette attorno ai valori degli attributi. Il codifica Un aggressore inserisce come didascalia dell'immagine una stringa abilmente costruita `foo onload=alert('Hacked!')`. Sappiamo già che Twig non può riconoscere se la variabile viene stampata nel flusso del testo HTML, all'interno di un attributo, di un commento HTML, ecc., in breve non distingue i contesti. E converte meccanicamente solo i caratteri `< > & ' "` in entità HTML. Quindi il codice risultante sarà simile a questo: -```html +```latte foo ``` @@ -330,7 +330,7 @@ Ora vediamo come Latte gestisce lo stesso template: Latte vede il template come lo vedi tu. A differenza di Twig, capisce HTML e sa che la variabile viene stampata come valore di un attributo che non è tra virgolette. Pertanto le aggiunge. Quando l'aggressore inserisce la stessa didascalia, il codice risultante sarà simile a questo: -```html +```latte foo onload=alert('Hacked!') ``` diff --git a/latte/it/type-system.texy b/latte/it/type-system.texy index ae98829c21..a5fb971b3c 100644 --- a/latte/it/type-system.texy +++ b/latte/it/type-system.texy @@ -21,7 +21,7 @@ Come iniziare a usare i tipi? Create una classe di template, ad es. `CatalogTemp class CatalogTemplateParameters { public function __construct( - public string $langs, + public string $lang, /** @var ProductEntity[] */ public array $products, public Address $address, @@ -35,7 +35,7 @@ $latte->render('template.latte', new CatalogTemplateParameters( )); ``` -Quindi, all'inizio del template, inserite il tag `{templateType}` con il nome completo della classe (incluso il namespace). Questo definisce che nel template ci sono le variabili `$langs` e `$products` con i rispettivi tipi. Potete specificare i tipi delle variabili locali usando i tag [`{var}` |tags#var default], `{varType}`, [`{define}` |template-inheritance#Definizioni define]. +Quindi, all'inizio del template, inserite il tag `{templateType}` con il nome completo della classe (incluso il namespace). Questo definisce che nel template ci sono le variabili `$lang` e `$products` con i rispettivi tipi. Potete specificare i tipi delle variabili locali usando i tag [`{var}` |tags#var default], `{varType}`, [`{define}` |template-inheritance#Definizioni define]. Da quel momento, l'IDE può suggerire correttamente. diff --git a/latte/ja/@menu.texy b/latte/ja/@menu.texy index 3ddf9860f6..8b6d85a875 100644 --- a/latte/ja/@menu.texy +++ b/latte/ja/@menu.texy @@ -5,8 +5,8 @@ diff --git a/latte/ja/@meta.texy b/latte/ja/@meta.texy new file mode 100644 index 0000000000..70f3f2da3d --- /dev/null +++ b/latte/ja/@meta.texy @@ -0,0 +1 @@ +{{sitename: Latte ドキュメンテーション}} diff --git a/latte/ja/cookbook/@home.texy b/latte/ja/cookbook/@home.texy index c1ecd21fec..60e83fedbc 100644 --- a/latte/ja/cookbook/@home.texy +++ b/latte/ja/cookbook/@home.texy @@ -11,5 +11,3 @@ Latteを使用して一般的なタスクを実行するためのコード例と - [PHP からの移行 |migration-from-php] - [Twig からの移行 |migration-from-twig] - [Slim 4 で Latte を使用する |slim-framework] - -{{leftbar: /@left-menu}} diff --git a/latte/ja/cookbook/@meta.texy b/latte/ja/cookbook/@meta.texy new file mode 100644 index 0000000000..fc4493feb0 --- /dev/null +++ b/latte/ja/cookbook/@meta.texy @@ -0,0 +1,2 @@ +{{sitename: Latte ドキュメンテーション}} +{{leftbar: /@left-menu}} diff --git a/latte/ja/cookbook/grouping.texy b/latte/ja/cookbook/grouping.texy index 85b325e0cd..bca2b47186 100644 --- a/latte/ja/cookbook/grouping.texy +++ b/latte/ja/cookbook/grouping.texy @@ -249,6 +249,3 @@ Nette Database と組み合わせてデータのグループ化を効果的に {/foreach} ``` - - -{{leftbar: /@left-menu}} diff --git a/latte/ja/cookbook/how-to-write-sql-queries-in-latte.texy b/latte/ja/cookbook/how-to-write-sql-queries-in-latte.texy index 5ad3e8988c..2f619ee6ee 100644 --- a/latte/ja/cookbook/how-to-write-sql-queries-in-latte.texy +++ b/latte/ja/cookbook/how-to-write-sql-queries-in-latte.texy @@ -38,5 +38,3 @@ $result = $db->query($sql); ``` *記載の例は Latte v3.0.5 以降が必要です。* - -{{leftbar: /@left-menu}} diff --git a/latte/ja/cookbook/migration-from-php.texy b/latte/ja/cookbook/migration-from-php.texy index 402ed76b88..94b53a2c46 100644 --- a/latte/ja/cookbook/migration-from-php.texy +++ b/latte/ja/cookbook/migration-from-php.texy @@ -2,7 +2,7 @@ PHP から Latte への移行 ***************** .[perex] -純粋な PHP で書かれた古いプロジェクトを Latte に変換していますか?移行を容易にするツールがあります。[オンラインでお試しください |https://php2latte.nette.org]。 +純粋な PHP で書かれた古いプロジェクトを Latte に変換していますか?移行を容易にするツールがあります。[オンラインでお試しください |https://fiddle.nette.org/php2latte/]。 ツールは [GitHub|https://github.com/nette/latte-tools] からダウンロードするか、Composer を使用してインストールできます: @@ -68,5 +68,3 @@ foreach ($result as $cur_group) {
``` - -{{leftbar: /@left-menu}} diff --git a/latte/ja/cookbook/migration-from-twig.texy b/latte/ja/cookbook/migration-from-twig.texy index 747e1c92e0..cd6d872fd8 100644 --- a/latte/ja/cookbook/migration-from-twig.texy +++ b/latte/ja/cookbook/migration-from-twig.texy @@ -2,7 +2,7 @@ Twig から Latte への移行 ****************** .[perex] -Twig で書かれたプロジェクトをよりモダンな Latte に変換していますか?移行を容易にするツールがあります。[オンラインでお試しください |https://twig2latte.nette.org]。 +Twig で書かれたプロジェクトをよりモダンな Latte に変換していますか?移行を容易にするツールがあります。[オンラインでお試しください |https://fiddle.nette.org/twig2latte/]。 ツールは [GitHub|https://github.com/nette/latte-tools] からダウンロードするか、Composer を使用してインストールできます: @@ -77,5 +77,3 @@ Latte に変換すると、次のテンプレートが得られます: ``` - -{{leftbar: /@left-menu}} diff --git a/latte/ja/cookbook/passing-variables.texy b/latte/ja/cookbook/passing-variables.texy index 4b5f5b01fd..828faab09d 100644 --- a/latte/ja/cookbook/passing-variables.texy +++ b/latte/ja/cookbook/passing-variables.texy @@ -156,6 +156,3 @@ $latte->render('template.latte', ['userName' => 'Jan', 'userAge' => 30]); ```latte {sandbox 'secure.latte', data: $secureData} ``` - - -{{leftbar: /@left-menu}} diff --git a/latte/ja/cookbook/slim-framework.texy b/latte/ja/cookbook/slim-framework.texy index 14ee341168..7c0f73e82d 100644 --- a/latte/ja/cookbook/slim-framework.texy +++ b/latte/ja/cookbook/slim-framework.texy @@ -155,4 +155,3 @@ Three ``` {{priority: -1}} -{{leftbar: /@left-menu}} diff --git a/latte/ja/custom-tags.texy b/latte/ja/custom-tags.texy index a3114b7964..347975a50b 100644 --- a/latte/ja/custom-tags.texy +++ b/latte/ja/custom-tags.texy @@ -923,7 +923,7 @@ class MyLatteExtension extends Extension 生成されたHTML: -```html +```latte 削除 ``` diff --git a/latte/ja/safety-first.texy b/latte/ja/safety-first.texy index 15f0190eb4..1e2c48e606 100644 --- a/latte/ja/safety-first.texy +++ b/latte/ja/safety-first.texy @@ -33,7 +33,7 @@ echo '

検索結果: ' . $search . '

'; 攻撃者は、検索ボックス、ひいては変数 `$search` に任意の文字列、つまり `` のようなHTMLコードを入力できます。出力がサニタイズされていないため、表示されるページの一部になります: -```html +```latte

検索結果:

``` @@ -59,7 +59,7 @@ echo '' . $imageAlt . ''; 攻撃者は、説明として巧妙に作成された文字列 `" onload="alert('Hacked!')` を挿入するだけで、出力がサニタイズされていない場合、結果のコードは次のようになります: -```html +```latte ``` @@ -91,7 +91,7 @@ XSSからどのように防御しますか? コンテキストという言葉で正確には何を意味しますか?それは、出力されるデータのサニタイズに関する独自のルールを持つドキュメント内の場所です。それはドキュメントのタイプ(HTML、XML、CSS、JavaScript、プレーンテキストなど)に依存し、その特定の場所によって異なる場合があります。 例えば、HTMLドキュメントには、非常に異なるルールが適用される多くの場所(コンテキスト)があります。いくつあるか驚くかもしれません。ここに最初の4つがあります: -```html +```latte

#テキスト

@@ -108,7 +108,7 @@ HTMLコメント内では興味深いです。ここでは、エスケープにH コンテキストはネストすることもできます。これは、JavaScriptまたはCSSをHTMLに埋め込むときに発生します。これは2つの異なる方法、要素と属性で行うことができます: -```html +```latte @@ -132,7 +132,7 @@ HTMLコメント内では興味深いです。ここでは、エスケープにH HTMLテキストに出力する場合、この特定のケースでは、文字列に特別な意味を持つ文字が含まれていないため、置換を行う必要はありません。状況は、単一引用符で囲まれたHTML属性内に出力する場合に異なります。その場合、引用符をHTMLエンティティにエスケープする必要があります: -```html +```latte
``` @@ -152,13 +152,13 @@ alert('Rock\'n\'Roll'); このコードを ` ``` しかし、HTML属性に挿入したい場合は、さらに引用符をHTMLエンティティにエスケープする必要があります: -```html +```latte
``` @@ -170,7 +170,7 @@ https://example.org/?a=Jazz&b=Rock%27n%27Roll そして、この文字列を属性に出力するとき、このコンテキストに従ってエスケープを適用し、`&` を `&` に置き換えます: -```html +```latte ``` @@ -314,7 +314,7 @@ Latteはテンプレートをあなたと同じように見ます。HTML、XML 攻撃者は、画像の説明として巧妙に作成された文字列 `foo onload=alert('Hacked!')` を挿入します。Twigは、変数がHTMLテキストの流れの中、属性内、HTMLコメント内など、どこに出力されているかを判断できないこと、つまりコンテキストを区別しないことをすでに知っています。そして、文字 `< > & ' "` を機械的にHTMLエンティティに変換するだけです。 したがって、結果のコードは次のようになります: -```html +```latte foo ``` @@ -330,7 +330,7 @@ Latteはテンプレートをあなたと同じように見ます。HTML、XML Latteはテンプレートをあなたと同じように見ます。Twigとは異なり、HTMLを理解し、変数が引用符で囲まれていない属性の値として出力されていることを知っています。したがって、それらを補完します。攻撃者が同じ説明を挿入すると、結果のコードは次のようになります: -```html +```latte foo onload=alert('Hacked!') ``` diff --git a/latte/ja/type-system.texy b/latte/ja/type-system.texy index 74a8f15022..0f93ddc900 100644 --- a/latte/ja/type-system.texy +++ b/latte/ja/type-system.texy @@ -21,7 +21,7 @@ class CatalogTemplateParameters { public function __construct( - public string $langs, + public string $lang, /** @var ProductEntity[] */ public array $products, public Address $address, @@ -35,7 +35,7 @@ $latte->render('template.latte', new CatalogTemplateParameters( )); ``` -次に、テンプレートの先頭に、クラスの完全な名前(名前空間を含む)を持つ `{templateType}` タグを挿入します。これにより、テンプレート内に変数 `$langs` と `$products` が、対応する型とともに定義されます。ローカル変数の型は、[`{var}` |tags#var default]、`{varType}`、[`{define}` |template-inheritance#Definitions] タグを使用して指定できます。 +次に、テンプレートの先頭に、クラスの完全な名前(名前空間を含む)を持つ `{templateType}` タグを挿入します。これにより、テンプレート内に変数 `$lang` と `$products` が、対応する型とともに定義されます。ローカル変数の型は、[`{var}` |tags#var default]、`{varType}`、[`{define}` |template-inheritance#Definitions] タグを使用して指定できます。 その時点から、IDEは正しく補完できるようになります。 diff --git a/latte/pl/@menu.texy b/latte/pl/@menu.texy index 4849ef8a75..df7bec843f 100644 --- a/latte/pl/@menu.texy +++ b/latte/pl/@menu.texy @@ -5,8 +5,8 @@ diff --git a/latte/pl/@meta.texy b/latte/pl/@meta.texy new file mode 100644 index 0000000000..82ad276beb --- /dev/null +++ b/latte/pl/@meta.texy @@ -0,0 +1 @@ +{{sitename: Dokumentacja Latte}} diff --git a/latte/pl/cookbook/@home.texy b/latte/pl/cookbook/@home.texy index 17c7113269..fb55d74650 100644 --- a/latte/pl/cookbook/@home.texy +++ b/latte/pl/cookbook/@home.texy @@ -11,5 +11,3 @@ Przykłady kodów i przepisów do wykonywania typowych zadań za pomocą Latte. - [Migracja z PHP |migration-from-php] - [Migracja z Twiga |migration-from-twig] - [Użycie Latte ze Slim 4 |slim-framework] - -{{leftbar: /@left-menu}} diff --git a/latte/pl/cookbook/@meta.texy b/latte/pl/cookbook/@meta.texy new file mode 100644 index 0000000000..53f435e908 --- /dev/null +++ b/latte/pl/cookbook/@meta.texy @@ -0,0 +1,2 @@ +{{sitename: Dokumentacja Latte}} +{{leftbar: /@left-menu}} diff --git a/latte/pl/cookbook/grouping.texy b/latte/pl/cookbook/grouping.texy index 3b23fe605f..c7fd154b2e 100644 --- a/latte/pl/cookbook/grouping.texy +++ b/latte/pl/cookbook/grouping.texy @@ -249,6 +249,3 @@ Załóżmy, że w tabeli będzie jeszcze dodatkowa kolumna `subcategoryId` i opr {/foreach} ``` - - -{{leftbar: /@left-menu}} diff --git a/latte/pl/cookbook/how-to-write-sql-queries-in-latte.texy b/latte/pl/cookbook/how-to-write-sql-queries-in-latte.texy index b1b3081da4..4173fa5570 100644 --- a/latte/pl/cookbook/how-to-write-sql-queries-in-latte.texy +++ b/latte/pl/cookbook/how-to-write-sql-queries-in-latte.texy @@ -38,5 +38,3 @@ $result = $db->query($sql); ``` *Podany przykład wymaga Latte w wersji 3.0.5 lub wyższej.* - -{{leftbar: /@left-menu}} diff --git a/latte/pl/cookbook/migration-from-php.texy b/latte/pl/cookbook/migration-from-php.texy index a484d7de5b..7993706c34 100644 --- a/latte/pl/cookbook/migration-from-php.texy +++ b/latte/pl/cookbook/migration-from-php.texy @@ -2,7 +2,7 @@ Migracja z PHP do Latte *********************** .[perex] -Konwertujesz stary projekt napisany w czystym PHP do Latte? Mamy dla Ciebie narzędzie, które ułatwi migrację. [Wypróbuj online |https://php2latte.nette.org]. +Konwertujesz stary projekt napisany w czystym PHP do Latte? Mamy dla Ciebie narzędzie, które ułatwi migrację. [Wypróbuj online |https://fiddle.nette.org/php2latte/]. Narzędzie możesz pobrać z [GitHub|https://github.com/nette/latte-tools] lub zainstalować za pomocą Composera: @@ -68,5 +68,3 @@ Wygeneruje ten szablon:
``` - -{{leftbar: /@left-menu}} diff --git a/latte/pl/cookbook/migration-from-twig.texy b/latte/pl/cookbook/migration-from-twig.texy index 4bfd395393..41aa0e395a 100644 --- a/latte/pl/cookbook/migration-from-twig.texy +++ b/latte/pl/cookbook/migration-from-twig.texy @@ -2,7 +2,7 @@ Migracja z Twig do Latte ************************ .[perex] -Konwertujesz projekt napisany w Twigu do nowocześniejszego Latte? Mamy dla Ciebie narzędzie, które ułatwi migrację. [Wypróbuj online |https://twig2latte.nette.org]. +Konwertujesz projekt napisany w Twigu do nowocześniejszego Latte? Mamy dla Ciebie narzędzie, które ułatwi migrację. [Wypróbuj online |https://fiddle.nette.org/twig2latte/]. Narzędzie możesz pobrać z [GitHub|https://github.com/nette/latte-tools] lub zainstalować za pomocą Composera: @@ -77,5 +77,3 @@ Po konwersji do Latte otrzymamy ten szablon: ``` - -{{leftbar: /@left-menu}} diff --git a/latte/pl/cookbook/passing-variables.texy b/latte/pl/cookbook/passing-variables.texy index 69101b6ade..3ad76a2e53 100644 --- a/latte/pl/cookbook/passing-variables.texy +++ b/latte/pl/cookbook/passing-variables.texy @@ -156,6 +156,3 @@ Tag `{sandbox}` izoluje szablon do bezpiecznego przetwarzania. Zmienne są przek ```latte {sandbox 'secure.latte', data: $secureData} ``` - - -{{leftbar: /@left-menu}} diff --git a/latte/pl/cookbook/slim-framework.texy b/latte/pl/cookbook/slim-framework.texy index fb8ea6c3a4..9afe988e39 100644 --- a/latte/pl/cookbook/slim-framework.texy +++ b/latte/pl/cookbook/slim-framework.texy @@ -155,4 +155,3 @@ Three ``` {{priority: -1}} -{{leftbar: /@left-menu}} diff --git a/latte/pl/custom-tags.texy b/latte/pl/custom-tags.texy index 50be9f0562..8dd42d7929 100644 --- a/latte/pl/custom-tags.texy +++ b/latte/pl/custom-tags.texy @@ -923,7 +923,7 @@ Teraz możesz użyć `n:confirm` na linkach, przyciskach lub elementach formular Wygenerowany HTML: -```html +```latte Usuń ``` diff --git a/latte/pl/safety-first.texy b/latte/pl/safety-first.texy index dc1f49265c..d8a666e1d7 100644 --- a/latte/pl/safety-first.texy +++ b/latte/pl/safety-first.texy @@ -33,7 +33,7 @@ echo '

Wyniki wyszukiwania dla ' . $search . '

'; Atakujący może w polu wyszukiwania, a tym samym w zmiennej `$search`, wpisać dowolny ciąg znaków, czyli również kod HTML, taki jak ``. Ponieważ wyjście nie jest w żaden sposób oczyszczone, stanie się częścią wyświetlonej strony: -```html +```latte

Wyniki wyszukiwania dla

``` @@ -59,7 +59,7 @@ echo '' . $imageAlt . ''; Atakującemu wystarczy jako opis wstawić sprytnie skonstruowany ciąg `" onload="alert('Hacked!')`, a jeśli wyświetlanie nie zostanie oczyszczone, wynikowy kod będzie wyglądał tak: -```html +```latte ``` @@ -91,7 +91,7 @@ Escapowanie kontekstowe Co dokładnie oznacza słowo kontekst? Jest to miejsce w dokumencie z własnymi zasadami oczyszczania wyświetlanych danych. Zależy od typu dokumentu (HTML, XML, CSS, JavaScript, plain text, ...) i może się różnić w jego poszczególnych częściach. Na przykład w dokumencie HTML istnieje wiele takich miejsc (kontekstów), gdzie obowiązują bardzo różne zasady. Być może będziesz zaskoczony, ile ich jest. Oto pierwsza czwórka: -```html +```latte

#text

@@ -108,7 +108,7 @@ Ciekawie jest wewnątrz komentarzy HTML. Tutaj bowiem do escapowania nie używa Konteksty mogą się również nakładać, co ma miejsce, gdy wstawiamy JavaScript lub CSS do HTML. Można to zrobić na dwa różne sposoby, elementem i atrybutem: -```html +```latte @@ -132,7 +132,7 @@ Miejmy ciąg `Rock'n'Roll`. Jeśli będziesz go wyświetlać w tekście HTML, akurat w tym przypadku nie trzeba dokonywać żadnych zamian, ponieważ ciąg nie zawiera żadnego znaku o specjalnym znaczeniu. Inna sytuacja nastąpi, jeśli wyświetlisz go wewnątrz atrybutu HTML ujętego w pojedyncze cudzysłowy. W takim przypadku trzeba escapować cudzysłowy na encje HTML: -```html +```latte
``` @@ -152,13 +152,13 @@ alert('Rock\'n\'Roll'); Jeśli ten kod wstawimy do dokumentu HTML za pomocą ` ``` Jeśli jednak chcielibyśmy go wstawić do atrybutu HTML, musimy jeszcze escapować cudzysłowy na encje HTML: -```html +```latte
``` @@ -170,7 +170,7 @@ https://example.org/?a=Jazz&b=Rock%27n%27Roll A kiedy ten ciąg wyświetlimy w atrybucie, jeszcze zastosujemy escapowanie zgodnie z tym kontekstem i zastąpimy `&` na `&`: -```html +```latte ``` @@ -314,7 +314,7 @@ Zwróć uwagę, że wokół wartości atrybutów nie ma cudzysłowów. Koder mó Atakujący jako opis obrazka wstawia sprytnie skonstruowany ciąg `foo onload=alert('Hacked!')`. Już wiemy, że Twig nie może rozpoznać, czy zmienna jest wyświetlana w przepływie tekstu HTML, wewnątrz atrybutu, komentarza HTML itp., krótko mówiąc, nie rozróżnia kontekstów. I tylko mechanicznie konwertuje znaki `< > & ' "` na encje HTML. Więc wynikowy kod będzie wyglądał tak: -```html +```latte foo ``` @@ -330,7 +330,7 @@ Teraz zobaczymy, jak z tym samym szablonem poradzi sobie Latte: Latte widzi szablon tak samo jak Ty. W przeciwieństwie do Twiga rozumie HTML i wie, że zmienna jest wyświetlana jako wartość atrybutu, który nie jest w cudzysłowach. Dlatego je uzupełni. Kiedy atakujący wstawi ten sam opis, wynikowy kod będzie wyglądał tak: -```html +```latte foo onload=alert('Hacked!') ``` diff --git a/latte/pl/type-system.texy b/latte/pl/type-system.texy index 3715e6a9d5..9f19e935d9 100644 --- a/latte/pl/type-system.texy +++ b/latte/pl/type-system.texy @@ -21,7 +21,7 @@ Jak zacząć używać typów? Utwórz klasę szablonu, np. `CatalogTemplateParam class CatalogTemplateParameters { public function __construct( - public string $langs, + public string $lang, /** @var ProductEntity[] */ public array $products, public Address $address, @@ -35,7 +35,7 @@ $latte->render('template.latte', new CatalogTemplateParameters( )); ``` -A następnie na początku szablonu wstaw tag `{templateType}` z pełną nazwą klasy (włącznie z namespace). To definiuje, że w szablonie są zmienne `$langs` i `$products` wraz z odpowiednimi typami. Typy zmiennych lokalnych możesz podać za pomocą tagów [`{var}` |tags#var default], `{varType}`, [`{define}` |template-inheritance#Definicje define]. +A następnie na początku szablonu wstaw tag `{templateType}` z pełną nazwą klasy (włącznie z namespace). To definiuje, że w szablonie są zmienne `$lang` i `$products` wraz z odpowiednimi typami. Typy zmiennych lokalnych możesz podać za pomocą tagów [`{var}` |tags#var default], `{varType}`, [`{define}` |template-inheritance#Definicje define]. Od tego momentu IDE może poprawnie podpowiadać. diff --git a/latte/pt/@menu.texy b/latte/pt/@menu.texy index 816f5c312f..894d36ea7a 100644 --- a/latte/pt/@menu.texy +++ b/latte/pt/@menu.texy @@ -5,8 +5,8 @@ diff --git a/latte/pt/@meta.texy b/latte/pt/@meta.texy new file mode 100644 index 0000000000..669a1b52fc --- /dev/null +++ b/latte/pt/@meta.texy @@ -0,0 +1 @@ +{{sitename: Documentação Latte}} diff --git a/latte/pt/cookbook/@home.texy b/latte/pt/cookbook/@home.texy index 4743144571..2f9f3a4baf 100644 --- a/latte/pt/cookbook/@home.texy +++ b/latte/pt/cookbook/@home.texy @@ -11,5 +11,3 @@ Exemplos de código e receitas para realizar tarefas comuns usando Latte. - [Migração do PHP |migration-from-php] - [Migração do Twig |migration-from-twig] - [Usando Latte com Slim 4 |slim-framework] - -{{leftbar: /@left-menu}} diff --git a/latte/pt/cookbook/@meta.texy b/latte/pt/cookbook/@meta.texy new file mode 100644 index 0000000000..45bfac38e1 --- /dev/null +++ b/latte/pt/cookbook/@meta.texy @@ -0,0 +1,2 @@ +{{sitename: Documentação Latte}} +{{leftbar: /@left-menu}} diff --git a/latte/pt/cookbook/grouping.texy b/latte/pt/cookbook/grouping.texy index 3b92a3c901..1fc19964ca 100644 --- a/latte/pt/cookbook/grouping.texy +++ b/latte/pt/cookbook/grouping.texy @@ -249,6 +249,3 @@ Digamos que na tabela haja outra coluna `subcategoryId` e, além de cada categor {/foreach} ``` - - -{{leftbar: /@left-menu}} diff --git a/latte/pt/cookbook/how-to-write-sql-queries-in-latte.texy b/latte/pt/cookbook/how-to-write-sql-queries-in-latte.texy index 7ccd9a6f68..b3a716691e 100644 --- a/latte/pt/cookbook/how-to-write-sql-queries-in-latte.texy +++ b/latte/pt/cookbook/how-to-write-sql-queries-in-latte.texy @@ -38,5 +38,3 @@ $result = $db->query($sql); ``` *O exemplo fornecido requer Latte v3.0.5 ou superior.* - -{{leftbar: /@left-menu}} diff --git a/latte/pt/cookbook/migration-from-php.texy b/latte/pt/cookbook/migration-from-php.texy index fd89504769..89c66f574e 100644 --- a/latte/pt/cookbook/migration-from-php.texy +++ b/latte/pt/cookbook/migration-from-php.texy @@ -2,7 +2,7 @@ Migração de PHP para Latte ************************** .[perex] -Está convertendo um projeto antigo escrito em PHP puro para Latte? Temos uma ferramenta para facilitar a migração. [Experimente online |https://php2latte.nette.org]. +Está convertendo um projeto antigo escrito em PHP puro para Latte? Temos uma ferramenta para facilitar a migração. [Experimente online |https://fiddle.nette.org/php2latte/]. Você pode baixar a ferramenta do [GitHub|https://github.com/nette/latte-tools] ou instalá-la usando o Composer: @@ -68,5 +68,3 @@ Ele gera este template:
``` - -{{leftbar: /@left-menu}} diff --git a/latte/pt/cookbook/migration-from-twig.texy b/latte/pt/cookbook/migration-from-twig.texy index 2f7c477850..a6c99ab2bb 100644 --- a/latte/pt/cookbook/migration-from-twig.texy +++ b/latte/pt/cookbook/migration-from-twig.texy @@ -2,7 +2,7 @@ Migração de Twig para Latte *************************** .[perex] -Está convertendo um projeto escrito em Twig para o mais moderno Latte? Temos uma ferramenta para facilitar a migração. [Experimente online |https://twig2latte.nette.org]. +Está convertendo um projeto escrito em Twig para o mais moderno Latte? Temos uma ferramenta para facilitar a migração. [Experimente online |https://fiddle.nette.org/twig2latte/]. Você pode baixar a ferramenta do [GitHub|https://github.com/nette/latte-tools] ou instalá-la usando o Composer: @@ -77,5 +77,3 @@ Após a conversão para Latte, obtemos este template: ``` - -{{leftbar: /@left-menu}} diff --git a/latte/pt/cookbook/passing-variables.texy b/latte/pt/cookbook/passing-variables.texy index 455059fce0..4c6478fda8 100644 --- a/latte/pt/cookbook/passing-variables.texy +++ b/latte/pt/cookbook/passing-variables.texy @@ -156,6 +156,3 @@ A tag `{sandbox}` isola o template para processamento seguro. As variáveis são ```latte {sandbox 'secure.latte', data: $secureData} ``` - - -{{leftbar: /@left-menu}} diff --git a/latte/pt/cookbook/slim-framework.texy b/latte/pt/cookbook/slim-framework.texy index 0cdc0ccf75..cdbf336263 100644 --- a/latte/pt/cookbook/slim-framework.texy +++ b/latte/pt/cookbook/slim-framework.texy @@ -155,4 +155,3 @@ Three ``` {{priority: -1}} -{{leftbar: /@left-menu}} diff --git a/latte/pt/custom-tags.texy b/latte/pt/custom-tags.texy index b080e9e20b..1e523ed866 100644 --- a/latte/pt/custom-tags.texy +++ b/latte/pt/custom-tags.texy @@ -923,7 +923,7 @@ Agora você pode usar `n:confirm` em links, botões ou elementos de formulário: HTML gerado: -```html +```latte Excluir ``` diff --git a/latte/pt/safety-first.texy b/latte/pt/safety-first.texy index 049ff1ae25..5e0351605c 100644 --- a/latte/pt/safety-first.texy +++ b/latte/pt/safety-first.texy @@ -33,7 +33,7 @@ echo '

Resultados da pesquisa para ' . $search . '

'; Um atacante pode inserir na caixa de pesquisa e, consequentemente, na variável `$search`, qualquer string, ou seja, também código HTML como ``. Como a saída não é tratada de forma alguma, ela torna-se parte da página exibida: -```html +```latte

Resultados da pesquisa para

``` @@ -59,7 +59,7 @@ echo '' . $imageAlt . ''; Basta ao atacante inserir como legenda uma string habilmente construída `" onload="alert('Hacked!')` e, se a exibição não for tratada, o código resultante será assim: -```html +```latte ``` @@ -91,7 +91,7 @@ Escaping sensível ao contexto O que exatamente se entende pela palavra contexto? É um local no documento com as suas próprias regras para o tratamento dos dados exibidos. Depende do tipo de documento (HTML, XML, CSS, JavaScript, texto simples, ...) e pode diferir nas suas partes específicas. Por exemplo, num documento HTML, existem muitos desses locais (contextos), onde regras muito diferentes se aplicam. Pode surpreender-se com quantos existem. Aqui temos os quatro primeiros: -```html +```latte

#texto

@@ -108,7 +108,7 @@ Pode surpreender-se, mas regras especiais aplicam-se dentro dos elementos `#js-elemento @@ -132,7 +132,7 @@ Tenha a string `Rock'n'Roll`. Se a exibir em texto HTML, neste caso específico não é necessário fazer nenhuma substituição, pois a string não contém nenhum caractere com significado especial. A situação muda se a exibir dentro de um atributo HTML delimitado por aspas simples. Nesse caso, é necessário escapar as aspas para entidades HTML: -```html +```latte
``` @@ -152,13 +152,13 @@ alert('Rock\'n\'Roll'); Se inserirmos este código num documento HTML usando ` ``` No entanto, se quiséssemos inseri-lo num atributo HTML, ainda precisaríamos de escapar as aspas para entidades HTML: -```html +```latte
``` @@ -170,7 +170,7 @@ https://example.org/?a=Jazz&b=Rock%27n%27Roll E quando exibimos esta string num atributo, ainda aplicamos o escaping de acordo com este contexto e substituímos `&` por `&`: -```html +```latte ``` @@ -314,7 +314,7 @@ Observe que não há aspas em torno dos valores dos atributos. O codificador pod Um atacante insere como legenda da imagem uma string habilmente construída `foo onload=alert('Hacked!')`. Já sabemos que o Twig não pode saber se a variável está a ser exibida no fluxo de texto HTML, dentro de um atributo, comentário HTML, etc., em suma, não distingue contextos. E apenas converte mecanicamente os caracteres `< > & ' "` em entidades HTML. Então, o código resultante será assim: -```html +```latte foo ``` @@ -330,7 +330,7 @@ Agora veremos como o Latte lida com o mesmo template: O Latte vê o template da mesma forma que você. Ao contrário do Twig, ele entende HTML e sabe que a variável está a ser exibida como o valor de um atributo que não está entre aspas. Portanto, ele adiciona-as. Quando o atacante insere a mesma legenda, o código resultante será assim: -```html +```latte foo onload=alert('Hacked!') ``` diff --git a/latte/pt/type-system.texy b/latte/pt/type-system.texy index 110047b4b4..9baf8bb9f8 100644 --- a/latte/pt/type-system.texy +++ b/latte/pt/type-system.texy @@ -21,7 +21,7 @@ Como começar a usar tipos? Crie uma classe de template, por exemplo, `CatalogTe class CatalogTemplateParameters { public function __construct( - public string $langs, + public string $lang, /** @var ProductEntity[] */ public array $products, public Address $address, @@ -35,7 +35,7 @@ $latte->render('template.latte', new CatalogTemplateParameters( )); ``` -E, em seguida, no início do template, insira a tag `{templateType}` com o nome completo da classe (incluindo o namespace). Isso define que no template existem as variáveis `$langs` e `$products`, incluindo os tipos correspondentes. Você pode especificar os tipos de variáveis locais usando as tags [`{var}` |tags#var default], `{varType}`, [`{define}` |template-inheritance#Definições]. +E, em seguida, no início do template, insira a tag `{templateType}` com o nome completo da classe (incluindo o namespace). Isso define que no template existem as variáveis `$lang` e `$products`, incluindo os tipos correspondentes. Você pode especificar os tipos de variáveis locais usando as tags [`{var}` |tags#var default], `{varType}`, [`{define}` |template-inheritance#Definições]. A partir desse momento, o IDE pode sugerir corretamente. diff --git a/latte/ro/@menu.texy b/latte/ro/@menu.texy index 12e7b8986b..2f4bc14d04 100644 --- a/latte/ro/@menu.texy +++ b/latte/ro/@menu.texy @@ -5,8 +5,8 @@ diff --git a/latte/ro/@meta.texy b/latte/ro/@meta.texy new file mode 100644 index 0000000000..3130122e97 --- /dev/null +++ b/latte/ro/@meta.texy @@ -0,0 +1 @@ +{{sitename: Documentație Latte}} diff --git a/latte/ro/cookbook/@home.texy b/latte/ro/cookbook/@home.texy index 53a946b1a5..f60f9b890a 100644 --- a/latte/ro/cookbook/@home.texy +++ b/latte/ro/cookbook/@home.texy @@ -11,5 +11,3 @@ Exemple de cod și rețete pentru efectuarea sarcinilor comune folosind Latte. - [Migrarea de la PHP |migration-from-php] - [Migrarea de la Twig |migration-from-twig] - [Utilizarea Latte cu Slim 4 |slim-framework] - -{{leftbar: /@left-menu}} diff --git a/latte/ro/cookbook/@meta.texy b/latte/ro/cookbook/@meta.texy new file mode 100644 index 0000000000..8339242327 --- /dev/null +++ b/latte/ro/cookbook/@meta.texy @@ -0,0 +1,2 @@ +{{sitename: Documentație Latte}} +{{leftbar: /@left-menu}} diff --git a/latte/ro/cookbook/grouping.texy b/latte/ro/cookbook/grouping.texy index d00c1ac8ca..3a88ef65d1 100644 --- a/latte/ro/cookbook/grouping.texy +++ b/latte/ro/cookbook/grouping.texy @@ -249,6 +249,3 @@ Să presupunem că în tabel va mai exista o coloană `subcategoryId` și, pe l {/foreach} ``` - - -{{leftbar: /@left-menu}} diff --git a/latte/ro/cookbook/how-to-write-sql-queries-in-latte.texy b/latte/ro/cookbook/how-to-write-sql-queries-in-latte.texy index c2dd127e49..833a0a15d9 100644 --- a/latte/ro/cookbook/how-to-write-sql-queries-in-latte.texy +++ b/latte/ro/cookbook/how-to-write-sql-queries-in-latte.texy @@ -38,5 +38,3 @@ $result = $db->query($sql); ``` *Exemplul prezentat necesită Latte v3.0.5 sau o versiune ulterioară.* - -{{leftbar: /@left-menu}} diff --git a/latte/ro/cookbook/migration-from-php.texy b/latte/ro/cookbook/migration-from-php.texy index fa648a9078..334754dea4 100644 --- a/latte/ro/cookbook/migration-from-php.texy +++ b/latte/ro/cookbook/migration-from-php.texy @@ -2,7 +2,7 @@ Migrarea de la PHP la Latte *************************** .[perex] -Convertiți un proiect vechi scris în PHP pur la Latte? Avem pentru dvs. un instrument care vă va facilita migrarea. [Încercați online |https://php2latte.nette.org]. +Convertiți un proiect vechi scris în PHP pur la Latte? Avem pentru dvs. un instrument care vă va facilita migrarea. [Încercați online |https://fiddle.nette.org/php2latte/]. Instrumentul îl puteți descărca de pe [GitHub |https://github.com/nette/latte-tools] sau instala folosind Composer: @@ -68,5 +68,3 @@ Generează acest șablon:
``` - -{{leftbar: /@left-menu}} diff --git a/latte/ro/cookbook/migration-from-twig.texy b/latte/ro/cookbook/migration-from-twig.texy index 97a4d4f49c..db1590587a 100644 --- a/latte/ro/cookbook/migration-from-twig.texy +++ b/latte/ro/cookbook/migration-from-twig.texy @@ -2,7 +2,7 @@ Migrarea de la Twig la Latte **************************** .[perex] -Convertiți un proiect scris în Twig la Latte, mai modern? Avem pentru dvs. un instrument care vă va facilita migrarea. [Încercați online |https://twig2latte.nette.org]. +Convertiți un proiect scris în Twig la Latte, mai modern? Avem pentru dvs. un instrument care vă va facilita migrarea. [Încercați online |https://fiddle.nette.org/twig2latte/]. Instrumentul îl puteți descărca de pe [GitHub |https://github.com/nette/latte-tools] sau instala folosind Composer: @@ -77,5 +77,3 @@ După conversia la Latte, obținem acest șablon: ``` - -{{leftbar: /@left-menu}} diff --git a/latte/ro/cookbook/passing-variables.texy b/latte/ro/cookbook/passing-variables.texy index 2dc904670f..2db71fcf00 100644 --- a/latte/ro/cookbook/passing-variables.texy +++ b/latte/ro/cookbook/passing-variables.texy @@ -156,6 +156,3 @@ Tag-ul `{sandbox}` izolează șablonul pentru procesare sigură. Variabilele sun ```latte {sandbox 'secure.latte', data: $secureData} ``` - - -{{leftbar: /@left-menu}} diff --git a/latte/ro/cookbook/slim-framework.texy b/latte/ro/cookbook/slim-framework.texy index 94942f17ad..1e06b5e764 100644 --- a/latte/ro/cookbook/slim-framework.texy +++ b/latte/ro/cookbook/slim-framework.texy @@ -155,4 +155,3 @@ Three ``` {{priority: -1}} -{{leftbar: /@left-menu}} diff --git a/latte/ro/custom-tags.texy b/latte/ro/custom-tags.texy index bc12920a37..3c353caabb 100644 --- a/latte/ro/custom-tags.texy +++ b/latte/ro/custom-tags.texy @@ -923,7 +923,7 @@ Acum puteți utiliza `n:confirm` pe linkuri, butoane sau elemente de formular: HTML generat: -```html +```latte Șterge ``` diff --git a/latte/ro/safety-first.texy b/latte/ro/safety-first.texy index 8140ba61d3..b4948a948d 100644 --- a/latte/ro/safety-first.texy +++ b/latte/ro/safety-first.texy @@ -33,7 +33,7 @@ echo '

Rezultatele căutării pentru ' . $search . '

'; Un atacator poate introduce în câmpul de căutare și, implicit, în variabila `$search`, orice șir, deci și cod HTML precum ``. Deoarece ieșirea nu este tratată în niciun fel, aceasta devine parte a paginii afișate: -```html +```latte

Rezultatele căutării pentru

``` @@ -59,7 +59,7 @@ echo '' . $imageAlt . ''; Atacatorului îi este suficient să introducă ca descriere un șir inteligent construit `" onload="alert('Hacked!')` și dacă afișarea nu este tratată, codul rezultat va arăta astfel: -```html +```latte ``` @@ -91,7 +91,7 @@ Escapare contextuală sensibilă Ce se înțelege exact prin cuvântul context? Este un loc în document cu propriile reguli pentru tratarea datelor afișate. Depinde de tipul documentului (HTML, XML, CSS, JavaScript, plain text, ...) și poate diferi în părțile sale specifice. De exemplu, într-un document HTML există o serie întreagă de astfel de locuri (contexte) unde se aplică reguli foarte diferite. Poate veți fi surprinși câte sunt. Iată primele patru: -```html +```latte

#text

@@ -108,7 +108,7 @@ Interesant este în interiorul comentariilor HTML. Aici, escaparea nu se face fo Contexturile se pot și stratifica, ceea ce se întâmplă când inserăm JavaScript sau CSS în HTML. Acest lucru se poate face în două moduri diferite, prin element și atribut: -```html +```latte @@ -132,7 +132,7 @@ Să avem șirul `Rock'n'Roll`. Dacă îl veți afișa în text HTML, în acest caz particular nu este nevoie de nicio înlocuire, deoarece șirul nu conține niciun caracter cu semnificație specială. Situația se schimbă dacă îl afișați în interiorul unui atribut HTML delimitat de apostrofuri simple. În acest caz, este necesar să escapați apostrofurile în entități HTML: -```html +```latte
``` @@ -152,13 +152,13 @@ alert('Rock\'n\'Roll'); Dacă inserăm acest cod într-un document HTML folosind ` ``` Dacă am dori însă să îl inserăm într-un atribut HTML, trebuie să mai escapăm ghilimelele în entități HTML: -```html +```latte
``` @@ -170,7 +170,7 @@ https://example.org/?a=Jazz&b=Rock%27n%27Roll Și când afișăm acest șir într-un atribut, aplicăm și escaparea conform acestui context și înlocuim `&` cu `&`: -```html +```latte ``` @@ -314,7 +314,7 @@ Observați că în jurul valorilor atributelor nu există ghilimele. Coderul le- Atacatorul introduce ca descriere a imaginii un șir inteligent construit `foo onload=alert('Hacked!')`. Știm deja că Twig nu poate recunoaște dacă variabila se afișează în fluxul textului HTML, în interiorul unui atribut, comentariu HTML etc., pe scurt, nu distinge contextele. Și doar convertesc mecanic caracterele `< > & ' "` în entități HTML. Deci, codul rezultat va arăta astfel: -```html +```latte foo ``` @@ -330,7 +330,7 @@ Acum să vedem cum se descurcă Latte cu același șablon: Latte vede șablonul la fel ca dvs. Spre deosebire de Twig, înțelege HTML și știe că variabila se afișează ca valoare a unui atribut care nu este între ghilimele. De aceea, le completează. Când atacatorul introduce aceeași descriere, codul rezultat va arăta astfel: -```html +```latte foo onload=alert('Hacked!') ``` diff --git a/latte/ro/type-system.texy b/latte/ro/type-system.texy index fc64e5ef84..508abcd9ee 100644 --- a/latte/ro/type-system.texy +++ b/latte/ro/type-system.texy @@ -21,7 +21,7 @@ Cum să începeți să utilizați tipurile? Creați o clasă de șablon, de exem class CatalogTemplateParameters { public function __construct( - public string $langs, + public string $lang, /** @var ProductEntity[] */ public array $products, public Address $address, @@ -35,7 +35,7 @@ $latte->render('template.latte', new CatalogTemplateParameters( )); ``` -Și apoi, la începutul șablonului, introduceți tag-ul `{templateType}` cu numele complet al clasei (inclusiv namespace). Acest lucru definește că în șablon există variabilele `$langs` și `$products` inclusiv tipurile corespunzătoare. Tipurile variabilelor locale pot fi specificate folosind tag-urile [`{var}` |tags#var default], `{varType}`, [`{define}` |template-inheritance#Definiții define]. +Și apoi, la începutul șablonului, introduceți tag-ul `{templateType}` cu numele complet al clasei (inclusiv namespace). Acest lucru definește că în șablon există variabilele `$lang` și `$products` inclusiv tipurile corespunzătoare. Tipurile variabilelor locale pot fi specificate folosind tag-urile [`{var}` |tags#var default], `{varType}`, [`{define}` |template-inheritance#Definiții define]. Din acel moment, IDE-ul vă poate oferi sugestii corecte. diff --git a/latte/ru/@menu.texy b/latte/ru/@menu.texy index d3e0b40c5a..b888f18d89 100644 --- a/latte/ru/@menu.texy +++ b/latte/ru/@menu.texy @@ -5,8 +5,8 @@ diff --git a/latte/ru/@meta.texy b/latte/ru/@meta.texy new file mode 100644 index 0000000000..c35f265d72 --- /dev/null +++ b/latte/ru/@meta.texy @@ -0,0 +1 @@ +{{sitename: Документация Latte}} diff --git a/latte/ru/cookbook/@home.texy b/latte/ru/cookbook/@home.texy index bac9ffd818..cb27293102 100644 --- a/latte/ru/cookbook/@home.texy +++ b/latte/ru/cookbook/@home.texy @@ -11,5 +11,3 @@ - [Миграция с PHP |migration-from-php] - [Миграция с Twig |migration-from-twig] - [Использование Latte со Slim 4 |slim-framework] - -{{leftbar: /@left-menu}} diff --git a/latte/ru/cookbook/@meta.texy b/latte/ru/cookbook/@meta.texy new file mode 100644 index 0000000000..6a8b9fa34b --- /dev/null +++ b/latte/ru/cookbook/@meta.texy @@ -0,0 +1,2 @@ +{{sitename: Документация Latte}} +{{leftbar: /@left-menu}} diff --git a/latte/ru/cookbook/grouping.texy b/latte/ru/cookbook/grouping.texy index 591a2bb767..853e9a1b77 100644 --- a/latte/ru/cookbook/grouping.texy +++ b/latte/ru/cookbook/grouping.texy @@ -249,6 +249,3 @@ {/foreach} ``` - - -{{leftbar: /@left-menu}} diff --git a/latte/ru/cookbook/how-to-write-sql-queries-in-latte.texy b/latte/ru/cookbook/how-to-write-sql-queries-in-latte.texy index 3da2d3d4d1..5ceff78a7e 100644 --- a/latte/ru/cookbook/how-to-write-sql-queries-in-latte.texy +++ b/latte/ru/cookbook/how-to-write-sql-queries-in-latte.texy @@ -38,5 +38,3 @@ $result = $db->query($sql); ``` *Приведенный пример требует Latte v3.0.5 или выше.* - -{{leftbar: /@left-menu}} diff --git a/latte/ru/cookbook/migration-from-php.texy b/latte/ru/cookbook/migration-from-php.texy index b8a7f191a9..21a2a0aa5b 100644 --- a/latte/ru/cookbook/migration-from-php.texy +++ b/latte/ru/cookbook/migration-from-php.texy @@ -2,7 +2,7 @@ *********************** .[perex] -Преобразуете старый проект, написанный на чистом PHP, в Latte? У нас есть инструмент, который облегчит вам миграцию. [Попробуйте его онлайн |https://php2latte.nette.org]. +Преобразуете старый проект, написанный на чистом PHP, в Latte? У нас есть инструмент, который облегчит вам миграцию. [Попробуйте его онлайн |https://fiddle.nette.org/php2latte/]. Инструмент можно скачать с [GitHub |https://github.com/nette/latte-tools] или установить с помощью Composer: @@ -68,5 +68,3 @@ foreach ($result as $cur_group) {
``` - -{{leftbar: /@left-menu}} diff --git a/latte/ru/cookbook/migration-from-twig.texy b/latte/ru/cookbook/migration-from-twig.texy index 38ad69f0e7..19ec6e9c89 100644 --- a/latte/ru/cookbook/migration-from-twig.texy +++ b/latte/ru/cookbook/migration-from-twig.texy @@ -2,7 +2,7 @@ ************************ .[perex] -Преобразуете проект, написанный на Twig, в более современный Latte? У нас есть инструмент, который облегчит вам миграцию. [Попробуйте его онлайн |https://twig2latte.nette.org]. +Преобразуете проект, написанный на Twig, в более современный Latte? У нас есть инструмент, который облегчит вам миграцию. [Попробуйте его онлайн |https://fiddle.nette.org/twig2latte/]. Инструмент можно скачать с [GitHub|https://github.com/nette/latte-tools] или установить с помощью Composer: @@ -77,5 +77,3 @@ php twig-to-latte.php input.twig.html [output.latte] ``` - -{{leftbar: /@left-menu}} diff --git a/latte/ru/cookbook/passing-variables.texy b/latte/ru/cookbook/passing-variables.texy index 0e1c37aa72..694694f73e 100644 --- a/latte/ru/cookbook/passing-variables.texy +++ b/latte/ru/cookbook/passing-variables.texy @@ -156,6 +156,3 @@ $latte->render('template.latte', ['userName' => 'Ян', 'userAge' => 30]); ```latte {sandbox 'secure.latte', data: $secureData} ``` - - -{{leftbar: /@left-menu}} diff --git a/latte/ru/cookbook/slim-framework.texy b/latte/ru/cookbook/slim-framework.texy index cb927a86fb..be54426a45 100644 --- a/latte/ru/cookbook/slim-framework.texy +++ b/latte/ru/cookbook/slim-framework.texy @@ -155,4 +155,3 @@ Three ``` {{priority: -1}} -{{leftbar: /@left-menu}} diff --git a/latte/ru/custom-tags.texy b/latte/ru/custom-tags.texy index dc35fdad01..3c0cd691eb 100644 --- a/latte/ru/custom-tags.texy +++ b/latte/ru/custom-tags.texy @@ -923,7 +923,7 @@ class MyLatteExtension extends Extension Сгенерированный HTML: -```html +```latte Удалить ``` diff --git a/latte/ru/safety-first.texy b/latte/ru/safety-first.texy index 96b91313cc..ffd79d93c4 100644 --- a/latte/ru/safety-first.texy +++ b/latte/ru/safety-first.texy @@ -33,7 +33,7 @@ echo '

Результаты поиска для ' . $search . '

'; Злоумышленник может в поле поиска и, соответственно, в переменную `$search` записать любую строку, в том числе и HTML-код, например ``. Поскольку вывод никак не обрабатывается, он станет частью отображаемой страницы: -```html +```latte

Результаты поиска для

``` @@ -59,7 +59,7 @@ echo '' . $imageAlt . ''; Злоумышленнику достаточно в качестве описания вставить хитро составленную строку `" onload="alert('Hacked!')`, и если вывод не будет обработан, результирующий код будет выглядеть так: -```html +```latte ``` @@ -91,7 +91,7 @@ echo '' . $imageAlt . ''; Что именно подразумевается под словом контекст? Это место в документе со своими правилами обработки выводимых данных. Зависит от типа документа (HTML, XML, CSS, JavaScript, plain text, ...) и может отличаться в его конкретных частях. Например, в HTML-документе таких мест (контекстов), где действуют очень разные правила, целое множество. Возможно, вы удивитесь, сколько их. Вот первая четверка: -```html +```latte

#текст

@@ -108,7 +108,7 @@ echo '' . $imageAlt . ''; Контексты также могут вкладываться, что происходит, когда мы вставляем JavaScript или CSS в HTML. Это можно сделать двумя разными способами, элементом и атрибутом: -```html +```latte @@ -132,7 +132,7 @@ echo '' . $imageAlt . ''; Если вы будете выводить ее в HTML-тексте, то в данном случае не нужно делать никаких замен, потому что строка не содержит ни одного символа со специальным значением. Другая ситуация возникнет, если вы выведете ее внутри HTML-атрибута, заключенного в одинарные кавычки. В таком случае необходимо экранировать кавычки в HTML-сущности: -```html +```latte
``` @@ -152,13 +152,13 @@ alert('Rock\'n\'Roll'); Если этот код вставить в HTML-документ с помощью ` ``` Однако, если бы мы хотели вставить его в HTML-атрибут, нужно еще экранировать кавычки в HTML-сущности: -```html +```latte
``` @@ -170,7 +170,7 @@ https://example.org/?a=Jazz&b=Rock%27n%27Roll А когда мы выводим эту строку в атрибуте, еще применяем экранирование в соответствии с этим контекстом и заменяем `&` на `&`: -```html +```latte ``` @@ -314,7 +314,7 @@ Latte видит шаблон так же, как и вы. Он понимает Злоумышленник в качестве описания изображения вставляет хитро составленную строку `foo onload=alert('Hacked!')`. Мы уже знаем, что Twig не может определить, выводится ли переменная в потоке HTML-текста, внутри атрибута, HTML-комментария и т. д., короче говоря, не различает контексты. И просто механически преобразует символы `< > & ' "` в HTML-сущности. Так что результирующий код будет выглядеть так: -```html +```latte foo ``` @@ -330,7 +330,7 @@ Latte видит шаблон так же, как и вы. Он понимает Latte видит шаблон так же, как и вы. В отличие от Twig, он понимает HTML и знает, что переменная выводится как значение атрибута, который не заключен в кавычки. Поэтому он их добавит. Когда злоумышленник вставит то же описание, результирующий код будет выглядеть так: -```html +```latte foo onload=alert('Hacked!') ``` diff --git a/latte/ru/type-system.texy b/latte/ru/type-system.texy index 875667cde2..ab6a5a5d6f 100644 --- a/latte/ru/type-system.texy +++ b/latte/ru/type-system.texy @@ -21,7 +21,7 @@ class CatalogTemplateParameters { public function __construct( - public string $langs, + public string $lang, /** @var ProductEntity[] */ public array $products, public Address $address, @@ -35,7 +35,7 @@ $latte->render('template.latte', new CatalogTemplateParameters( )); ``` -А затем в начало шаблона вставьте тег `{templateType}` с полным именем класса (включая пространство имен). Это определяет, что в шаблоне есть переменные `$langs` и `$products` с соответствующими типами. Типы локальных переменных можно указать с помощью тегов [`{var}` |tags#var default], `{varType}`, [`{define}` |template-inheritance#Определения]. +А затем в начало шаблона вставьте тег `{templateType}` с полным именем класса (включая пространство имен). Это определяет, что в шаблоне есть переменные `$lang` и `$products` с соответствующими типами. Типы локальных переменных можно указать с помощью тегов [`{var}` |tags#var default], `{varType}`, [`{define}` |template-inheritance#Определения]. С этого момента IDE сможет правильно подсказывать. diff --git a/latte/sl/@menu.texy b/latte/sl/@menu.texy index c8abac1f48..a889e7dd37 100644 --- a/latte/sl/@menu.texy +++ b/latte/sl/@menu.texy @@ -5,8 +5,8 @@ diff --git a/latte/sl/@meta.texy b/latte/sl/@meta.texy new file mode 100644 index 0000000000..581c4735c1 --- /dev/null +++ b/latte/sl/@meta.texy @@ -0,0 +1 @@ +{{sitename: Latte Dokumentacija}} diff --git a/latte/sl/cookbook/@home.texy b/latte/sl/cookbook/@home.texy index b4ebdc2c9d..78376d6b75 100644 --- a/latte/sl/cookbook/@home.texy +++ b/latte/sl/cookbook/@home.texy @@ -11,5 +11,3 @@ Primeri kod in receptov za izvajanje pogostih nalog s pomočjo Latte. - [Migracija iz PHP |migration-from-php] - [Migracija iz Twiga |migration-from-twig] - [Uporaba Latte s Slim 4 |slim-framework] - -{{leftbar: /@left-menu}} diff --git a/latte/sl/cookbook/@meta.texy b/latte/sl/cookbook/@meta.texy new file mode 100644 index 0000000000..b8c17ced54 --- /dev/null +++ b/latte/sl/cookbook/@meta.texy @@ -0,0 +1,2 @@ +{{sitename: Latte Dokumentacija}} +{{leftbar: /@left-menu}} diff --git a/latte/sl/cookbook/grouping.texy b/latte/sl/cookbook/grouping.texy index 2e8ae46553..fdd016f1e9 100644 --- a/latte/sl/cookbook/grouping.texy +++ b/latte/sl/cookbook/grouping.texy @@ -249,6 +249,3 @@ Recimo, da bo v tabeli še en stolpec `subcategoryId` in poleg tega, da bo vsaka {/foreach} ``` - - -{{leftbar: /@left-menu}} diff --git a/latte/sl/cookbook/how-to-write-sql-queries-in-latte.texy b/latte/sl/cookbook/how-to-write-sql-queries-in-latte.texy index 3188fd03e2..465de2a83f 100644 --- a/latte/sl/cookbook/how-to-write-sql-queries-in-latte.texy +++ b/latte/sl/cookbook/how-to-write-sql-queries-in-latte.texy @@ -38,5 +38,3 @@ $result = $db->query($sql); ``` *Navedeni primer zahteva Latte v3.0.5 ali višjo.* - -{{leftbar: /@left-menu}} diff --git a/latte/sl/cookbook/migration-from-php.texy b/latte/sl/cookbook/migration-from-php.texy index 3cc59e1d7a..d3482bc5b6 100644 --- a/latte/sl/cookbook/migration-from-php.texy +++ b/latte/sl/cookbook/migration-from-php.texy @@ -2,7 +2,7 @@ Migracija iz PHP v Latte ************************ .[perex] -Prevajate star projekt, napisan v čistem PHP, v Latte? Imamo orodje za vas, ki vam bo olajšalo migracijo. [Preizkusite na spletu |https://php2latte.nette.org]. +Prevajate star projekt, napisan v čistem PHP, v Latte? Imamo orodje za vas, ki vam bo olajšalo migracijo. [Preizkusite na spletu |https://fiddle.nette.org/php2latte/]. Orodje si lahko prenesete z [GitHubu|https://github.com/nette/latte-tools] ali namestite s pomočjo Composerja: @@ -68,5 +68,3 @@ Generira to predlogo:
``` - -{{leftbar: /@left-menu}} diff --git a/latte/sl/cookbook/migration-from-twig.texy b/latte/sl/cookbook/migration-from-twig.texy index 849b844037..50a45b3e58 100644 --- a/latte/sl/cookbook/migration-from-twig.texy +++ b/latte/sl/cookbook/migration-from-twig.texy @@ -2,7 +2,7 @@ Migracija iz Twiga v Latte ************************** .[perex] -Prevajate projekt, napisan v Twigu, v sodobnejši Latte? Imamo orodje za vas, ki vam bo olajšalo migracijo. [Preizkusite na spletu |https://twig2latte.nette.org]. +Prevajate projekt, napisan v Twigu, v sodobnejši Latte? Imamo orodje za vas, ki vam bo olajšalo migracijo. [Preizkusite na spletu |https://fiddle.nette.org/twig2latte/]. Orodje si lahko prenesete z [GitHubu|https://github.com/nette/latte-tools] ali namestite s pomočjo Composerja: @@ -77,5 +77,3 @@ Po pretvorbi v Latte dobimo to predlogo: ``` - -{{leftbar: /@left-menu}} diff --git a/latte/sl/cookbook/passing-variables.texy b/latte/sl/cookbook/passing-variables.texy index 203c0c1320..7fe561de3f 100644 --- a/latte/sl/cookbook/passing-variables.texy +++ b/latte/sl/cookbook/passing-variables.texy @@ -156,6 +156,3 @@ Oznaka `{sandbox}` izolira predlogo za varno obdelavo. Spremenljivke se prenaša ```latte {sandbox 'secure.latte', data: $secureData} ``` - - -{{leftbar: /@left-menu}} diff --git a/latte/sl/cookbook/slim-framework.texy b/latte/sl/cookbook/slim-framework.texy index 52d4b514cf..bac9b71ab0 100644 --- a/latte/sl/cookbook/slim-framework.texy +++ b/latte/sl/cookbook/slim-framework.texy @@ -155,4 +155,3 @@ Three ``` {{priority: -1}} -{{leftbar: /@left-menu}} diff --git a/latte/sl/custom-tags.texy b/latte/sl/custom-tags.texy index 1066b5eb86..1bb1570146 100644 --- a/latte/sl/custom-tags.texy +++ b/latte/sl/custom-tags.texy @@ -923,7 +923,7 @@ Zdaj lahko uporabite `n:confirm` na povezavah, gumbih ali elementih obrazca: Generirana HTML koda: -```html +```latte Izbriši ``` diff --git a/latte/sl/safety-first.texy b/latte/sl/safety-first.texy index 509802d6c8..29adc447e2 100644 --- a/latte/sl/safety-first.texy +++ b/latte/sl/safety-first.texy @@ -33,7 +33,7 @@ echo '

Rezultati iskanja za ' . $search . '

'; Napadalec lahko v iskalno polje in posledično v spremenljivko `$search` zapiše poljuben niz, torej tudi HTML kodo kot ``. Ker izpis ni nikakor obdelan, postane del prikazane strani: -```html +```latte

Rezultati iskanja za

``` @@ -59,7 +59,7 @@ echo '' . $imageAlt . ''; Napadalcu zadostuje, da kot opis vstavi spretno sestavljen niz `" onload="alert('Hacked!')` in če izpis ne bo obdelan, bo rezultatna koda izgledala takole: -```html +```latte ``` @@ -91,7 +91,7 @@ Kontekstno občutljivo ubežanje Kaj točno se misli z besedo kontekst? Gre za mesto v dokumentu z lastnimi pravili za obdelavo izpisanih podatkov. Odvisno je od vrste dokumenta (HTML, XML, CSS, JavaScript, navadno besedilo, ...) in se lahko razlikuje v njegovih konkretnih delih. Na primer, v dokumentu HTML je takih mest (kontekstov), kjer veljajo zelo različna pravila, cela vrsta. Morda boste presenečeni, koliko jih je. Tukaj imamo prvo četverico: -```html +```latte

#text

@@ -108,7 +108,7 @@ Zanimivo je znotraj komentarjev HTML. Tukaj se namreč za ubežanje ne uporablja Konteksti se lahko tudi plastijo, do česar pride, ko vstavimo JavaScript ali CSS v HTML. To je mogoče storiti na dva različna načina, z elementom in atributom: -```html +```latte @@ -132,7 +132,7 @@ Imejmo niz `Rock'n'Roll`. Če ga boste izpisovali v besedilu HTML, ravno v tem primeru ni treba delati nobenih zamenjav, ker niz ne vsebuje nobenega znaka s posebnim pomenom. Druga situacija nastane, če ga izpišete znotraj atributa HTML, omejenega z enojnimi narekovaji. V takem primeru je treba narekovaje ubežati v HTML entitete: -```html +```latte
``` @@ -152,13 +152,13 @@ alert('Rock\'n\'Roll'); Če to kodo vstavimo v dokument HTML s pomočjo ` ``` Če pa bi jo želeli vstaviti v atribut HTML, moramo še ubežati narekovaje v HTML entitete: -```html +```latte
``` @@ -170,7 +170,7 @@ https://example.org/?a=Jazz&b=Rock%27n%27Roll In ko ta niz izpišemo v atributu, še uporabimo ubežanje po tem kontekstu in zamenjamo `&` za `&`: -```html +```latte ``` @@ -314,7 +314,7 @@ Opazite, da okoli vrednosti atributov ni narekovajev. Koder jih je lahko pozabil Napadalec kot opis slike vstavi spretno sestavljen niz `foo onload=alert('Hacked!')`. Že vemo, da Twig ne more prepoznati, ali se spremenljivka izpisuje v toku besedila HTML, znotraj atributa, komentarja HTML, itd., skratka ne razlikuje kontekstov. In samo mehansko pretvarja znake `< > & ' "` v HTML entitete. Torej bo rezultatna koda izgledala takole: -```html +```latte foo ``` @@ -330,7 +330,7 @@ Zdaj si poglejmo, kako se z enako predlogo spopade Latte: Latte vidi predlogo enako kot vi. Za razliko od Twiga razume HTML in ve, da se spremenljivka izpisuje kot vrednost atributa, ki ni v narekovajih. Zato jih dopolni. Ko napadalec vstavi enak opis, bo rezultatna koda izgledala takole: -```html +```latte foo onload=alert('Hacked!') ``` diff --git a/latte/sl/type-system.texy b/latte/sl/type-system.texy index 09f661778b..e814b63fd0 100644 --- a/latte/sl/type-system.texy +++ b/latte/sl/type-system.texy @@ -21,7 +21,7 @@ Kako začeti uporabljati tipe? Ustvarite si razred predloge, npr. `CatalogTempla class CatalogTemplateParameters { public function __construct( - public string $langs, + public string $lang, /** @var ProductEntity[] */ public array $products, public Address $address, @@ -35,7 +35,7 @@ $latte->render('template.latte', new CatalogTemplateParameters( )); ``` -Nato na začetek predloge vstavite značko `{templateType}` s polnim imenom razreda (vključno z imenskim prostorom). To definira, da so v predlogi spremenljivke `$langs` in `$products` vključno z ustreznimi tipi. Tipe lokalnih spremenljivk lahko navedete s pomočjo značk [`{var}` |tags#var default], `{varType}`, [`{define}` |template-inheritance#Definicije]. +Nato na začetek predloge vstavite značko `{templateType}` s polnim imenom razreda (vključno z imenskim prostorom). To definira, da so v predlogi spremenljivke `$lang` in `$products` vključno z ustreznimi tipi. Tipe lokalnih spremenljivk lahko navedete s pomočjo značk [`{var}` |tags#var default], `{varType}`, [`{define}` |template-inheritance#Definicije]. Od takrat vam lahko IDE pravilno predlaga. diff --git a/latte/tr/@menu.texy b/latte/tr/@menu.texy index 0a7511b7c4..296875b7e0 100644 --- a/latte/tr/@menu.texy +++ b/latte/tr/@menu.texy @@ -5,8 +5,8 @@ diff --git a/latte/tr/@meta.texy b/latte/tr/@meta.texy new file mode 100644 index 0000000000..2aa1de2903 --- /dev/null +++ b/latte/tr/@meta.texy @@ -0,0 +1 @@ +{{sitename: Latte Dokümantasyonu}} diff --git a/latte/tr/cookbook/@home.texy b/latte/tr/cookbook/@home.texy index 52c338348e..1d1a94cb9b 100644 --- a/latte/tr/cookbook/@home.texy +++ b/latte/tr/cookbook/@home.texy @@ -11,5 +11,3 @@ Latte kullanarak yaygın görevleri gerçekleştirmek için kod örnekleri ve ta - [PHP'den Geçiş |migration-from-php] - [Twig'den Geçiş |migration-from-twig] - [Latte'yi Slim 4 ile Kullanma |slim-framework] - -{{leftbar: /@left-menu}} diff --git a/latte/tr/cookbook/@meta.texy b/latte/tr/cookbook/@meta.texy new file mode 100644 index 0000000000..24e8dea278 --- /dev/null +++ b/latte/tr/cookbook/@meta.texy @@ -0,0 +1,2 @@ +{{sitename: Latte Dokümantasyonu}} +{{leftbar: /@left-menu}} diff --git a/latte/tr/cookbook/grouping.texy b/latte/tr/cookbook/grouping.texy index 061f72b656..0115d141f1 100644 --- a/latte/tr/cookbook/grouping.texy +++ b/latte/tr/cookbook/grouping.texy @@ -249,6 +249,3 @@ Tabloda ek bir `subcategoryId` sütunu olduğunu ve her kategorinin ayrı bir `< {/foreach} ``` - - -{{leftbar: /@left-menu}} diff --git a/latte/tr/cookbook/how-to-write-sql-queries-in-latte.texy b/latte/tr/cookbook/how-to-write-sql-queries-in-latte.texy index bb546fe49d..29269805e0 100644 --- a/latte/tr/cookbook/how-to-write-sql-queries-in-latte.texy +++ b/latte/tr/cookbook/how-to-write-sql-queries-in-latte.texy @@ -38,5 +38,3 @@ $result = $db->query($sql); ``` *Belirtilen örnek Latte v3.0.5 veya üstünü gerektirir.* - -{{leftbar: /@left-menu}} diff --git a/latte/tr/cookbook/migration-from-php.texy b/latte/tr/cookbook/migration-from-php.texy index c9ff10c028..e63f8cb9c6 100644 --- a/latte/tr/cookbook/migration-from-php.texy +++ b/latte/tr/cookbook/migration-from-php.texy @@ -2,7 +2,7 @@ PHP'den Latte'ye Geçiş ********************** .[perex] -Saf PHP ile yazılmış eski bir projeyi Latte'ye mi dönüştürüyorsunuz? Geçişi kolaylaştıracak bir aracımız var. [Çevrimiçi deneyin |https://php2latte.nette.org]. +Saf PHP ile yazılmış eski bir projeyi Latte'ye mi dönüştürüyorsunuz? Geçişi kolaylaştıracak bir aracımız var. [Çevrimiçi deneyin |https://fiddle.nette.org/php2latte/]. Aracı [GitHub|https://github.com/nette/latte-tools]'dan indirebilir veya Composer kullanarak yükleyebilirsiniz: @@ -68,5 +68,3 @@ Bu şablonu oluşturur:
``` - -{{leftbar: /@left-menu}} diff --git a/latte/tr/cookbook/migration-from-twig.texy b/latte/tr/cookbook/migration-from-twig.texy index c25fb1e733..12e2bf8efb 100644 --- a/latte/tr/cookbook/migration-from-twig.texy +++ b/latte/tr/cookbook/migration-from-twig.texy @@ -2,7 +2,7 @@ Twig'den Latte'ye Geçiş *********************** .[perex] -Twig ile yazılmış bir projeyi daha modern Latte'ye mi dönüştürüyorsunuz? Geçişi kolaylaştıracak bir aracımız var. [Çevrimiçi deneyin |https://twig2latte.nette.org]. +Twig ile yazılmış bir projeyi daha modern Latte'ye mi dönüştürüyorsunuz? Geçişi kolaylaştıracak bir aracımız var. [Çevrimiçi deneyin |https://fiddle.nette.org/twig2latte/]. Aracı [GitHub|https://github.com/nette/latte-tools]'dan indirebilir veya Composer kullanarak yükleyebilirsiniz: @@ -77,5 +77,3 @@ Latte'ye dönüştürdükten sonra şu şablonu elde ederiz: ``` - -{{leftbar: /@left-menu}} diff --git a/latte/tr/cookbook/passing-variables.texy b/latte/tr/cookbook/passing-variables.texy index dcac9cbbf2..30d1277e88 100644 --- a/latte/tr/cookbook/passing-variables.texy +++ b/latte/tr/cookbook/passing-variables.texy @@ -156,6 +156,3 @@ Tersine, `{embed}` içindeki bloklarda tüm çevre değişkenlerine erişim vard ```latte {sandbox 'secure.latte', data: $secureData} ``` - - -{{leftbar: /@left-menu}} diff --git a/latte/tr/cookbook/slim-framework.texy b/latte/tr/cookbook/slim-framework.texy index dd1580eaf6..f84e21afd4 100644 --- a/latte/tr/cookbook/slim-framework.texy +++ b/latte/tr/cookbook/slim-framework.texy @@ -155,4 +155,3 @@ Three ``` {{priority: -1}} -{{leftbar: /@left-menu}} diff --git a/latte/tr/custom-tags.texy b/latte/tr/custom-tags.texy index 402e361e28..8f582915f0 100644 --- a/latte/tr/custom-tags.texy +++ b/latte/tr/custom-tags.texy @@ -923,7 +923,7 @@ class MyLatteExtension extends Extension Oluşturulan HTML: -```html +```latte Sil ``` diff --git a/latte/tr/safety-first.texy b/latte/tr/safety-first.texy index a4943315fd..9e550024e2 100644 --- a/latte/tr/safety-first.texy +++ b/latte/tr/safety-first.texy @@ -33,7 +33,7 @@ echo '

' . $search . ' için arama sonuçları

'; Saldırgan, arama kutusuna ve dolayısıyla `$search` değişkenine `` gibi HTML kodu da dahil olmak üzere herhangi bir karakter dizisi yazabilir. Çıktı hiçbir şekilde işlenmediği için, görüntülenen sayfanın bir parçası haline gelir: -```html +```latte

için arama sonuçları

``` @@ -59,7 +59,7 @@ echo '' . $imageAlt . ''; Saldırganın açıklama olarak akıllıca oluşturulmuş bir karakter dizisi `" onload="alert('Hacklendiniz!')` eklemesi yeterlidir ve yazdırma işlenmezse, sonuç kodu şöyle görünecektir: -```html +```latte ``` @@ -91,7 +91,7 @@ Bağlama Duyarlı Kaçış Bağlam kelimesiyle tam olarak ne kastediliyor? Belgenin içinde, yazdırılan verilerin işlenmesi için kendi kuralları olan bir yerdir. Belgenin türüne (HTML, XML, CSS, JavaScript, düz metin, ...) bağlıdır ve belirli bölümlerinde farklılık gösterebilir. Örneğin, bir HTML belgesinde, çok farklı kuralların geçerli olduğu birçok yer (bağlam) vardır. Kaç tane olduğuna şaşırabilirsiniz. İşte ilk dördü: -```html +```latte

#metin

@@ -108,7 +108,7 @@ HTML yorumlarının içi ilginçtir. Burada kaçış için HTML varlıkları kul Bağlamlar ayrıca katmanlanabilir, bu da HTML'e JavaScript veya CSS eklediğimizde olur. Bu iki farklı şekilde yapılabilir, öğe ve nitelik ile: -```html +```latte @@ -132,7 +132,7 @@ Bir Örnek İster misiniz? Bunu HTML metninde yazdırırsanız, bu özel durumda herhangi bir değiştirme yapmaya gerek yoktur, çünkü dize özel anlamı olan hiçbir karakter içermez. Tek tırnak içine alınmış bir HTML niteliği içinde yazdırırsanız durum farklıdır. Bu durumda, tırnak işaretlerini HTML varlıklarına kaçış işlemine tabi tutmak gerekir: -```html +```latte
``` @@ -152,13 +152,13 @@ alert('Rock\'n\'Roll'); Bu kodu ` ``` Ancak bunu bir HTML niteliğine eklemek istersek, tırnak işaretlerini de HTML varlıklarına kaçış işlemine tabi tutmamız gerekir: -```html +```latte
``` @@ -170,7 +170,7 @@ https://example.org/?a=Jazz&b=Rock%27n%27Roll Ve bu dizeyi bir nitelikte yazdırdığımızda, bu bağlama göre kaçış işlemini de uygular ve `&` yerine `&` yazarız: -```html +```latte ``` @@ -314,7 +314,7 @@ Nitelik değerlerinin etrafında tırnak işareti olmadığına dikkat edin. Kod Saldırgan, resim açıklaması olarak akıllıca oluşturulmuş bir karakter dizisi `foo onload=alert('Hacklendiniz!')` ekler. Twig'in değişkenin HTML metin akışında mı, bir nitelik içinde mi, HTML yorumunda mı vb. yazdırıldığını anlayamayacağını, kısacası bağlamları ayırt etmediğini zaten biliyoruz. Ve yalnızca `< > & ' "` karakterlerini mekanik olarak HTML varlıklarına dönüştürür. Yani sonuç kodu şöyle görünecektir: -```html +```latte foo ``` @@ -330,7 +330,7 @@ Sahte `onload` niteliği sayfanın bir parçası haline geldi ve tarayıcı resm Latte şablonu sizin gördüğünüz gibi görür. Twig'in aksine, HTML'i anlar ve değişkenin tırnak içinde olmayan bir niteliğin değeri olarak yazdırıldığını bilir. Bu yüzden onları ekler. Saldırgan aynı açıklamayı eklediğinde, sonuç kodu şöyle görünecektir: -```html +```latte foo onload=alert('Hacklendiniz!') ``` diff --git a/latte/tr/type-system.texy b/latte/tr/type-system.texy index 005ce71f91..eaf4424ee5 100644 --- a/latte/tr/type-system.texy +++ b/latte/tr/type-system.texy @@ -21,7 +21,7 @@ Tipleri kullanmaya nasıl başlanır? İletilen parametreleri, tiplerini ve muht class CatalogTemplateParameters { public function __construct( - public string $langs, + public string $lang, /** @var ProductEntity[] */ public array $products, public Address $address, @@ -35,7 +35,7 @@ $latte->render('template.latte', new CatalogTemplateParameters( )); ``` -Ve ardından şablonun başına `{templateType}` etiketini sınıfın tam adıyla (ad alanı dahil) ekleyin. Bu, şablonda `$langs` ve `$products` değişkenlerinin ilgili tipleriyle birlikte bulunduğunu tanımlar. Yerel değişkenlerin tiplerini [`{var}` |tags#var default], `{varType}`, [`{define}` |template-inheritance#Tanımlar] etiketlerini kullanarak belirtebilirsiniz. +Ve ardından şablonun başına `{templateType}` etiketini sınıfın tam adıyla (ad alanı dahil) ekleyin. Bu, şablonda `$lang` ve `$products` değişkenlerinin ilgili tipleriyle birlikte bulunduğunu tanımlar. Yerel değişkenlerin tiplerini [`{var}` |tags#var default], `{varType}`, [`{define}` |template-inheritance#Tanımlar] etiketlerini kullanarak belirtebilirsiniz. O andan itibaren IDE size doğru önerilerde bulunabilir. diff --git a/latte/uk/@menu.texy b/latte/uk/@menu.texy index 8e37bfde7f..4300fe4f02 100644 --- a/latte/uk/@menu.texy +++ b/latte/uk/@menu.texy @@ -5,7 +5,7 @@ diff --git a/latte/uk/@meta.texy b/latte/uk/@meta.texy new file mode 100644 index 0000000000..984f2b2309 --- /dev/null +++ b/latte/uk/@meta.texy @@ -0,0 +1 @@ +{{sitename: Документація Latte}} diff --git a/latte/uk/cookbook/@home.texy b/latte/uk/cookbook/@home.texy index a57e2e0022..65cd916958 100644 --- a/latte/uk/cookbook/@home.texy +++ b/latte/uk/cookbook/@home.texy @@ -11,5 +11,3 @@ - [Міграція з PHP |migration-from-php] - [Міграція з Twig |migration-from-twig] - [Використання Latte зі Slim 4 |slim-framework] - -{{leftbar: /@left-menu}} diff --git a/latte/uk/cookbook/@meta.texy b/latte/uk/cookbook/@meta.texy new file mode 100644 index 0000000000..80e1df686d --- /dev/null +++ b/latte/uk/cookbook/@meta.texy @@ -0,0 +1,2 @@ +{{sitename: Документація Latte}} +{{leftbar: /@left-menu}} diff --git a/latte/uk/cookbook/grouping.texy b/latte/uk/cookbook/grouping.texy index a63b4d2ff4..e9a47c8a1e 100644 --- a/latte/uk/cookbook/grouping.texy +++ b/latte/uk/cookbook/grouping.texy @@ -249,6 +249,3 @@ {/foreach} ``` - - -{{leftbar: /@left-menu}} diff --git a/latte/uk/cookbook/how-to-write-sql-queries-in-latte.texy b/latte/uk/cookbook/how-to-write-sql-queries-in-latte.texy index 07b8c13524..4998decb92 100644 --- a/latte/uk/cookbook/how-to-write-sql-queries-in-latte.texy +++ b/latte/uk/cookbook/how-to-write-sql-queries-in-latte.texy @@ -38,5 +38,3 @@ $result = $db->query($sql); ``` *Наведений приклад вимагає Latte v3.0.5 або вище.* - -{{leftbar: /@left-menu}} diff --git a/latte/uk/cookbook/migration-from-php.texy b/latte/uk/cookbook/migration-from-php.texy index 2ac9124452..8dfa1c1701 100644 --- a/latte/uk/cookbook/migration-from-php.texy +++ b/latte/uk/cookbook/migration-from-php.texy @@ -2,7 +2,7 @@ *********************** .[perex] -Переносите старий проєкт, написаний на чистому PHP, на Latte? Ми маємо для вас інструмент, який полегшить міграцію. [Спробуйте онлайн |https://php2latte.nette.org]. +Переносите старий проєкт, написаний на чистому PHP, на Latte? Ми маємо для вас інструмент, який полегшить міграцію. [Спробуйте онлайн |https://fiddle.nette.org/php2latte/]. Інструмент можна завантажити з [GitHub|https://github.com/nette/latte-tools] або встановити за допомогою Composer: @@ -68,5 +68,3 @@ foreach ($result as $cur_group) {
``` - -{{leftbar: /@left-menu}} diff --git a/latte/uk/cookbook/migration-from-twig.texy b/latte/uk/cookbook/migration-from-twig.texy index 59ed4db5f4..a0748c5f81 100644 --- a/latte/uk/cookbook/migration-from-twig.texy +++ b/latte/uk/cookbook/migration-from-twig.texy @@ -2,7 +2,7 @@ ************************ .[perex] -Переносите проєкт, написаний на Twig, на сучасніший Latte? Ми маємо для вас інструмент, який полегшить міграцію. [Спробуйте онлайн |https://twig2latte.nette.org]. +Переносите проєкт, написаний на Twig, на сучасніший Latte? Ми маємо для вас інструмент, який полегшить міграцію. [Спробуйте онлайн |https://fiddle.nette.org/twig2latte/]. Інструмент можна завантажити з [GitHub|https://github.com/nette/latte-tools] або встановити за допомогою Composer: @@ -77,5 +77,3 @@ php twig-to-latte.php input.twig.html [output.latte] ``` - -{{leftbar: /@left-menu}} diff --git a/latte/uk/cookbook/passing-variables.texy b/latte/uk/cookbook/passing-variables.texy index 3434f0f39f..12c833c36f 100644 --- a/latte/uk/cookbook/passing-variables.texy +++ b/latte/uk/cookbook/passing-variables.texy @@ -156,6 +156,3 @@ $latte->render('template.latte', ['userName' => 'Jan', 'userAge' => 30]); ```latte {sandbox 'secure.latte', data: $secureData} ``` - - -{{leftbar: /@left-menu}} diff --git a/latte/uk/cookbook/slim-framework.texy b/latte/uk/cookbook/slim-framework.texy index 64a90f60dd..48edc7e12a 100644 --- a/latte/uk/cookbook/slim-framework.texy +++ b/latte/uk/cookbook/slim-framework.texy @@ -155,4 +155,3 @@ Three ``` {{priority: -1}} -{{leftbar: /@left-menu}} diff --git a/latte/uk/custom-tags.texy b/latte/uk/custom-tags.texy index 96af747f17..c2e63f4ab1 100644 --- a/latte/uk/custom-tags.texy +++ b/latte/uk/custom-tags.texy @@ -923,7 +923,7 @@ class MyLatteExtension extends Extension Згенерований HTML: -```html +```latte Видалити ``` diff --git a/latte/uk/safety-first.texy b/latte/uk/safety-first.texy index 60ff086270..b5fd634f04 100644 --- a/latte/uk/safety-first.texy +++ b/latte/uk/safety-first.texy @@ -33,7 +33,7 @@ echo '

Результати пошуку для ' . $search . '

'; Зловмисник може в поле пошуку і, відповідно, в змінну `$search` записати будь-який рядок, тобто і HTML-код, як ``. Оскільки вивід ніяк не обробляється, він стане частиною відображеної сторінки: -```html +```latte

Результати пошуку для

``` @@ -59,7 +59,7 @@ echo '' . $imageAlt . ''; Зловмиснику достатньо як опис вставити хитро складений рядок `" onload="alert('Hacked!')`, і якщо виведення не буде оброблено, кінцевий код виглядатиме так: -```html +```latte ``` @@ -91,7 +91,7 @@ echo '' . $imageAlt . ''; Що саме мається на увазі під словом контекст? Це місце в документі з власними правилами обробки виведених даних. Воно залежить від типу документа (HTML, XML, CSS, JavaScript, plain text, ...) і може відрізнятися в його конкретних частинах. Наприклад, в HTML-документі є ціла низка таких місць (контекстів), де діють дуже різні правила. Можливо, ви будете здивовані, скільки їх є. Ось перша четвірка: -```html +```latte

#text

@@ -108,7 +108,7 @@ echo '' . $imageAlt . ''; Контексти також можуть нашаровуватися, що відбувається, коли ми вставляємо JavaScript або CSS в HTML. Це можна зробити двома різними способами: елементом та атрибутом: -```html +```latte @@ -132,7 +132,7 @@ echo '' . $imageAlt . ''; Якщо ви будете виводити його в HTML-тексті, саме в цьому випадку не потрібно робити жодних замін, оскільки рядок не містить жодного символу зі спеціальним значенням. Інша ситуація виникне, якщо ви виведете його всередині HTML-атрибута, взятого в одинарні лапки. У такому випадку потрібно екранувати лапки на HTML-сутності: -```html +```latte
``` @@ -152,13 +152,13 @@ alert('Rock\'n\'Roll'); Якщо цей код вставити в HTML-документ за допомогою ` ``` Однак, якби ми хотіли вставити його в HTML-атрибут, ми повинні ще екранувати лапки на HTML-сутності: -```html +```latte
``` @@ -170,7 +170,7 @@ https://example.org/?a=Jazz&b=Rock%27n%27Roll І коли ми виводимо цей рядок в атрибуті, ще застосовуємо екранування відповідно до цього контексту і замінюємо `&` на `&`: -```html +```latte ``` @@ -314,7 +314,7 @@ Latte бачить шаблон так само, як і ви. Розуміє HT Зловмисник як опис зображення вставляє хитро складений рядок `foo onload=alert('Hacked!')`. Ми вже знаємо, що Twig не може розпізнати, чи виводиться змінна в потоці HTML-тексту, всередині атрибута, HTML-коментаря тощо, коротше кажучи, не розрізняє контексти. І лише механічно перетворює символи `< > & ' "` на HTML-сутності. Отже, кінцевий код виглядатиме так: -```html +```latte foo ``` @@ -330,7 +330,7 @@ Latte бачить шаблон так само, як і ви. Розуміє HT Latte бачить шаблон так само, як і ви. На відміну від Twig, він розуміє HTML і знає, що змінна виводиться як значення атрибута, який не взятий у лапки. Тому він їх доповнить. Коли зловмисник вставить той самий опис, кінцевий код виглядатиме так: -```html +```latte foo onload=alert('Hacked!') ``` diff --git a/latte/uk/type-system.texy b/latte/uk/type-system.texy index 9d6c08535b..14ea265b99 100644 --- a/latte/uk/type-system.texy +++ b/latte/uk/type-system.texy @@ -21,7 +21,7 @@ class CatalogTemplateParameters { public function __construct( - public string $langs, + public string $lang, /** @var ProductEntity[] */ public array $products, public Address $address, @@ -35,7 +35,7 @@ $latte->render('template.latte', new CatalogTemplateParameters( )); ``` -А далі на початку шаблону вставте тег `{templateType}` з повною назвою класу (включаючи простір імен). Це визначає, що в шаблоні є змінні `$langs` та `$products` з відповідними типами. Типи локальних змінних можна вказати за допомогою тегів [`{var}` |tags#var default], `{varType}`, [`{define}` |template-inheritance#Визначення]. +А далі на початку шаблону вставте тег `{templateType}` з повною назвою класу (включаючи простір імен). Це визначає, що в шаблоні є змінні `$lang` та `$products` з відповідними типами. Типи локальних змінних можна вказати за допомогою тегів [`{var}` |tags#var default], `{varType}`, [`{define}` |template-inheritance#Визначення]. З цього моменту ваше IDE може правильно підказувати. diff --git a/mail/bg/@home.texy b/mail/bg/@home.texy index 342bd57d6e..9c9eecc237 100644 --- a/mail/bg/@home.texy +++ b/mail/bg/@home.texy @@ -313,6 +313,3 @@ DI Сървиси |----------------------------------------------------- | `mail.mailer` | [api:Nette\Mail\Mailer] | [клас, изпращащ имейли |#Изпращане на имейл] | `mail.signer` | [api:Nette\Mail\Signer] | [DKIM подписване |#DKIM] - - -{{leftbar: nette:@menu-topics}} diff --git a/mail/bg/@meta.texy b/mail/bg/@meta.texy new file mode 100644 index 0000000000..794cbc8522 --- /dev/null +++ b/mail/bg/@meta.texy @@ -0,0 +1,2 @@ +{{sitename: Документация на Nette}} +{{leftbar: nette:@menu-topics}} diff --git a/mail/cs/@home.texy b/mail/cs/@home.texy index 39b718a0da..fb72bf092d 100644 --- a/mail/cs/@home.texy +++ b/mail/cs/@home.texy @@ -176,6 +176,78 @@ V šabloně potom vytváříme odkazy tak, jak jsme zvyklí. Všechny odkazy vyt ``` +Inlinování CSS +============== + +[api:Nette\Mail\CssInliner] převádí CSS pravidla na inline atributy `style`, aby se e-maily zobrazovaly správně ve všech klientech. Zároveň generuje HTML atributy pro kompatibilitu s Outlookem. + +.[note] +Vyžaduje PHP 8.4 nebo novější a rozšíření `dom`. + +Většina e-mailových klientů má omezenou podporu značky ` +

Hello world

+``` + +Výsledek po inlinování bude (značka ` +

Hello world

+``` + +The result after inlining will be (the ` + + + + + +

+ Code coverage 52 % + sources have 6,180 lines of code in 32 files +

+ + + +
+
+ + + + + + + + +
+  % + +
+
+ path  +
+
+
+ +
+ + + + + + diff --git a/tester/fr/@meta.texy b/tester/fr/@meta.texy new file mode 100644 index 0000000000..bf776a55f4 --- /dev/null +++ b/tester/fr/@meta.texy @@ -0,0 +1 @@ +{{sitename: Documentation Tester}} diff --git a/tester/fr/guide.texy b/tester/fr/guide.texy index b23bde0a9e..a1dfae8b35 100644 --- a/tester/fr/guide.texy +++ b/tester/fr/guide.texy @@ -152,7 +152,7 @@ Rapports CodeCoverage Tester peut générer des rapports donnant un aperçu de la quantité de code source couverte par les tests. Le rapport peut être soit au format HTML lisible par l'homme, soit en XML Clover pour un traitement machine ultérieur. -Consultez l'[exemple de rapport HTML |https://files.nette.org/tester/coverage.html] avec la couverture de code. +Consultez l'[exemple de rapport HTML |attachment:coverage.html] avec la couverture de code. Versions PHP supportées diff --git a/tester/fr/running-tests.texy b/tester/fr/running-tests.texy index 3d7ffb9793..aa15d8d55b 100644 --- a/tester/fr/running-tests.texy +++ b/tester/fr/running-tests.texy @@ -211,7 +211,7 @@ La priorité de sélection du mécanisme est la suivante : Lors de l'utilisation de PHPDBG, nous pouvons rencontrer un échec de test sur des tests volumineux en raison de l'épuisement de la mémoire. La collecte d'informations sur le code couvert est gourmande en mémoire. Dans ce cas, l'appel `Tester\CodeCoverage\Collector::flush()` à l'intérieur du test nous aide. Il écrit les données collectées sur le disque et libère la mémoire. Si la collecte de données n'a pas lieu, ou si Xdebug est utilisé, l'appel n'a aucun effet. -"Exemple de rapport HTML":https://files.nette.org/tester/coverage.html avec la couverture de code. +"Exemple de rapport HTML":attachment:coverage.html avec la couverture de code. --coverage-src .[filter] diff --git a/tester/hu/@meta.texy b/tester/hu/@meta.texy new file mode 100644 index 0000000000..6be4d2d1ff --- /dev/null +++ b/tester/hu/@meta.texy @@ -0,0 +1 @@ +{{sitename: Tester dokumentáció}} diff --git a/tester/hu/guide.texy b/tester/hu/guide.texy index e0f4bdd88e..d3ae1172b0 100644 --- a/tester/hu/guide.texy +++ b/tester/hu/guide.texy @@ -152,7 +152,7 @@ Kódlefedettségi jelentések A Tester képes jelentéseket generálni arról, hogy a tesztek mennyi forráskódot fednek le. A jelentés lehet ember által olvasható HTML formátumban, vagy Clover XML formátumban további gépi feldolgozáshoz. -Nézze meg a "HTML jelentés példája":https://files.nette.org/tester/coverage.html a kódlefedettséggel. +Nézze meg a "HTML jelentés példája":attachment:coverage.html a kódlefedettséggel. Támogatott PHP verziók diff --git a/tester/hu/running-tests.texy b/tester/hu/running-tests.texy index 834b8a48f2..e97e081cca 100644 --- a/tester/hu/running-tests.texy +++ b/tester/hu/running-tests.texy @@ -211,7 +211,7 @@ A mechanizmus kiválasztásának prioritása a következő: PHPDBG használatakor terjedelmes teszteknél előfordulhat, hogy a teszt memóriahiány miatt meghiúsul. A lefedett kódról szóló információk gyűjtése memóriaigényes. Ebben az esetben segít a `Tester\CodeCoverage\Collector::flush()` hívása a teszten belül. Kiírja az összegyűjtött adatokat a lemezre, és felszabadítja a memóriát. Ha az adatgyűjtés nem zajlik, vagy Xdebugot használunk, a hívásnak nincs hatása. -"HTML jelentés példája":https://files.nette.org/tester/coverage.html a kódlefedettséggel. +"HTML jelentés példája":attachment:coverage.html a kódlefedettséggel. --coverage-src .[filter] diff --git a/tester/it/@meta.texy b/tester/it/@meta.texy new file mode 100644 index 0000000000..ecccb16258 --- /dev/null +++ b/tester/it/@meta.texy @@ -0,0 +1 @@ +{{sitename: Documentazione Tester}} diff --git a/tester/it/guide.texy b/tester/it/guide.texy index 7011bea473..3336dcbe27 100644 --- a/tester/it/guide.texy +++ b/tester/it/guide.texy @@ -152,7 +152,7 @@ Report di Code Coverage Tester può generare report con una panoramica di quanto codice sorgente coprono i test. Il report può essere sia in formato HTML leggibile dall'uomo, sia in Clover XML per un'ulteriore elaborazione automatica. -Date un'occhiata a "un esempio di report HTML":https://files.nette.org/tester/coverage.html con la copertura del codice. +Date un'occhiata a "un esempio di report HTML":attachment:coverage.html con la copertura del codice. Versioni PHP supportate diff --git a/tester/it/running-tests.texy b/tester/it/running-tests.texy index a05bde55e2..1ef2648157 100644 --- a/tester/it/running-tests.texy +++ b/tester/it/running-tests.texy @@ -211,7 +211,7 @@ La priorità di selezione del meccanismo è la seguente: Utilizzando PHPDBG, possiamo riscontrare il fallimento del test a causa dell'esaurimento della memoria nei test estesi. La raccolta di informazioni sulla copertura del codice richiede molta memoria. In questo caso, ci aiuta la chiamata `Tester\CodeCoverage\Collector::flush()` all'interno del test. Scrive i dati raccolti su disco e libera la memoria. Se la raccolta dati non è in corso, o viene utilizzato Xdebug, la chiamata non ha alcun effetto. -"Esempio di report HTML":https://files.nette.org/tester/coverage.html con la copertura del codice. +"Esempio di report HTML":attachment:coverage.html con la copertura del codice. --coverage-src .[filter] diff --git a/tester/ja/@meta.texy b/tester/ja/@meta.texy new file mode 100644 index 0000000000..aa196b919b --- /dev/null +++ b/tester/ja/@meta.texy @@ -0,0 +1 @@ +{{sitename: Tester ドキュメンテーション}} diff --git a/tester/ja/guide.texy b/tester/ja/guide.texy index 536a5174f5..5d802b977e 100644 --- a/tester/ja/guide.texy +++ b/tester/ja/guide.texy @@ -152,7 +152,7 @@ Watch モードは [--watch |running-tests#-w --watch path] パラメータで Tester は、テストがソースコードのどれだけをカバーしているかの概要を示すレポートを生成できます。レポートは、人間が読める HTML 形式、またはさらなる機械処理のための Clover XML 形式のいずれかになります。 -コードカバレッジの "HTML レポートのサンプル":https://files.nette.org/tester/coverage.html をご覧ください。 +コードカバレッジの "HTML レポートのサンプル":attachment:coverage.html をご覧ください。 サポートされている PHP バージョン diff --git a/tester/ja/running-tests.texy b/tester/ja/running-tests.texy index 7ad823bebe..6a1ab46702 100644 --- a/tester/ja/running-tests.texy +++ b/tester/ja/running-tests.texy @@ -211,7 +211,7 @@ tester tests --coverage coverage.xml # Clover XML レポート PHPDBG を使用する場合、大規模なテストではメモリ不足のためにテストが失敗することがあります。コードカバレッジ情報の収集はメモリを大量に消費します。この場合、テスト内で `Tester\CodeCoverage\Collector::flush()` を呼び出すと役立ちます。収集されたデータをディスクに書き込み、メモリを解放します。データ収集が実行されていない場合、または Xdebug が使用されている場合、呼び出しは何の効果もありません。 -コードカバレッジの [HTML レポートのサンプル|https://files.nette.org/tester/coverage.html]。 +コードカバレッジの [HTML レポートのサンプル|attachment:coverage.html]。 --coverage-src .[filter] diff --git a/tester/pl/@meta.texy b/tester/pl/@meta.texy new file mode 100644 index 0000000000..c818b06e79 --- /dev/null +++ b/tester/pl/@meta.texy @@ -0,0 +1 @@ +{{sitename: Dokumentacja Tester}} diff --git a/tester/pl/guide.texy b/tester/pl/guide.texy index f6df5a54f2..876d446302 100644 --- a/tester/pl/guide.texy +++ b/tester/pl/guide.texy @@ -152,7 +152,7 @@ Raporty CodeCoverage Tester potrafi generować raporty z przeglądem, ile kodu źródłowego pokrywają testy. Raport może być albo w czytelnym dla człowieka formacie HTML, albo Clover XML do dalszego przetwarzania maszynowego. -Zobacz "przykładowy raport HTML":https://files.nette.org/tester/coverage.html z pokryciem kodu. +Zobacz "przykładowy raport HTML":attachment:coverage.html z pokryciem kodu. Obsługiwane wersje PHP diff --git a/tester/pl/running-tests.texy b/tester/pl/running-tests.texy index 0c34dbd327..bc8f9fb9b0 100644 --- a/tester/pl/running-tests.texy +++ b/tester/pl/running-tests.texy @@ -211,7 +211,7 @@ Priorytet wyboru mechanizmu jest następujący: Przy użyciu PHPDBG możemy przy obszernych testach napotkać na niepowodzenie testu z powodu wyczerpania pamięci. Zbieranie informacji o pokrytym kodzie jest pamięciochłonne. W tym przypadku pomoże nam wywołanie `Tester\CodeCoverage\Collector::flush()` wewnątrz testu. Zapisze zebrane dane na dysk i zwolni pamięć. Jeśli zbieranie danych nie przebiega lub jest używany Xdebug, wywołanie nie ma żadnego efektu. -"Przykładowy raport HTML":https://files.nette.org/tester/coverage.html z pokryciem kodu. +"Przykładowy raport HTML":attachment:coverage.html z pokryciem kodu. --coverage-src .[filter] diff --git a/tester/pt/@meta.texy b/tester/pt/@meta.texy new file mode 100644 index 0000000000..f3aa8429c5 --- /dev/null +++ b/tester/pt/@meta.texy @@ -0,0 +1 @@ +{{sitename: Documentação Tester}} diff --git a/tester/pt/guide.texy b/tester/pt/guide.texy index 10c3765130..9147968185 100644 --- a/tester/pt/guide.texy +++ b/tester/pt/guide.texy @@ -152,7 +152,7 @@ Relatórios de Cobertura de Código O Tester pode gerar relatórios com uma visão geral de quanto do código-fonte os testes cobrem. O relatório pode ser em formato HTML legível por humanos ou Clover XML para processamento posterior por máquina. -Veja um "exemplo de relatório HTML":https://files.nette.org/tester/coverage.html com cobertura de código. +Veja um "exemplo de relatório HTML":attachment:coverage.html com cobertura de código. Versões do PHP suportadas diff --git a/tester/pt/running-tests.texy b/tester/pt/running-tests.texy index b403f753dc..b07806393c 100644 --- a/tester/pt/running-tests.texy +++ b/tester/pt/running-tests.texy @@ -211,7 +211,7 @@ A prioridade de seleção do mecanismo é a seguinte: Ao usar PHPDBG, podemos encontrar falhas nos testes devido ao esgotamento da memória em testes extensos. A coleta de informações sobre o código coberto consome muita memória. Neste caso, a chamada `Tester\CodeCoverage\Collector::flush()` dentro do teste nos ajuda. Ela escreve os dados coletados no disco e libera a memória. Se a coleta de dados não estiver ocorrendo, ou se o Xdebug estiver sendo usado, a chamada não tem efeito. -"Exemplo de relatório HTML"|https://files.nette.org/tester/coverage.html com cobertura de código. +"Exemplo de relatório HTML"|attachment:coverage.html com cobertura de código. --coverage-src .[filter] diff --git a/tester/ro/@meta.texy b/tester/ro/@meta.texy new file mode 100644 index 0000000000..786a1fcbaa --- /dev/null +++ b/tester/ro/@meta.texy @@ -0,0 +1 @@ +{{sitename: Documentație Tester}} diff --git a/tester/ro/guide.texy b/tester/ro/guide.texy index edcf12761c..4afff18e8a 100644 --- a/tester/ro/guide.texy +++ b/tester/ro/guide.texy @@ -152,7 +152,7 @@ Rapoarte CodeCoverage Tester poate genera rapoarte cu o prezentare generală a cât de mult cod sursă acoperă testele. Raportul poate fi fie în format HTML lizibil pentru oameni, fie Clover XML pentru prelucrare automată ulterioară. -Consultați "exemplul de raport HTML":https://files.nette.org/tester/coverage.html cu acoperirea codului. +Consultați "exemplul de raport HTML":attachment:coverage.html cu acoperirea codului. Versiuni PHP suportate diff --git a/tester/ro/running-tests.texy b/tester/ro/running-tests.texy index 5382c50c44..37e379bb83 100644 --- a/tester/ro/running-tests.texy +++ b/tester/ro/running-tests.texy @@ -211,7 +211,7 @@ Prioritatea alegerii mecanismului este următoarea: La utilizarea PHPDBG, la testele extinse putem întâmpina eșecul testului din cauza epuizării memoriei. Colectarea informațiilor despre codul acoperit este consumatoare de memorie. În acest caz ne ajută apelul `Tester\CodeCoverage\Collector::flush()` în interiorul testului. Scrie datele colectate pe disc și eliberează memoria. Dacă colectarea datelor nu are loc sau se folosește Xdebug, apelul nu are niciun efect. -"Exemplu de raport HTML":https://files.nette.org/tester/coverage.html cu acoperirea codului. +"Exemplu de raport HTML":attachment:coverage.html cu acoperirea codului. --coverage-src .[filter] diff --git a/tester/ru/@meta.texy b/tester/ru/@meta.texy new file mode 100644 index 0000000000..1e1abb2619 --- /dev/null +++ b/tester/ru/@meta.texy @@ -0,0 +1 @@ +{{sitename: Документация Tester}} diff --git a/tester/ru/guide.texy b/tester/ru/guide.texy index 38e0509ef3..e390c0a949 100644 --- a/tester/ru/guide.texy +++ b/tester/ru/guide.texy @@ -152,7 +152,7 @@ PHP 8.3.2 (cli) | php -n | 8 threads Tester умеет генерировать отчеты с обзором того, сколько исходного кода покрывают тесты. Отчет может быть либо в читаемом человеком формате HTML, либо в Clover XML для дальнейшей машинной обработки. -Посмотрите "пример HTML отчета":https://files.nette.org/tester/coverage.html с покрытием кода. +Посмотрите "пример HTML отчета":attachment:coverage.html с покрытием кода. Поддерживаемые версии PHP diff --git a/tester/ru/running-tests.texy b/tester/ru/running-tests.texy index f59e88647e..1d5a03df43 100644 --- a/tester/ru/running-tests.texy +++ b/tester/ru/running-tests.texy @@ -211,7 +211,7 @@ tester tests --coverage coverage.xml # Clover XML отчет При использовании PHPDBG на объемных тестах можно столкнуться с отказом теста из-за исчерпания памяти. Сбор информации о покрытом коде требует много памяти. В этом случае нам поможет вызов `Tester\CodeCoverage\Collector::flush()` внутри теста. Он запишет собранные данные на диск и освободит память. Если сбор данных не происходит или используется Xdebug, вызов не имеет никакого эффекта. -"Пример HTML отчета":https://files.nette.org/tester/coverage.html с покрытием кода. +"Пример HTML отчета":attachment:coverage.html с покрытием кода. --coverage-src .[filter] diff --git a/tester/sl/@meta.texy b/tester/sl/@meta.texy new file mode 100644 index 0000000000..e7b3539264 --- /dev/null +++ b/tester/sl/@meta.texy @@ -0,0 +1 @@ +{{sitename: Tester Dokumentacija}} diff --git a/tester/sl/guide.texy b/tester/sl/guide.texy index a675663e75..e384cc4d88 100644 --- a/tester/sl/guide.texy +++ b/tester/sl/guide.texy @@ -152,7 +152,7 @@ CodeCoverage poročila Tester zna generirati poročila s pregledom, koliko izvorne kode testi pokrivajo. Poročilo je lahko bodisi v človeško berljivem formatu HTML ali Clover XML za nadaljnjo strojno obdelavo. -Poglejte si "vzorec HTML poročila":https://files.nette.org/tester/coverage.html s pokritostjo kode. +Poglejte si "vzorec HTML poročila":attachment:coverage.html s pokritostjo kode. Podprte različice PHP diff --git a/tester/sl/running-tests.texy b/tester/sl/running-tests.texy index e4a709d644..3c173a5039 100644 --- a/tester/sl/running-tests.texy +++ b/tester/sl/running-tests.texy @@ -211,7 +211,7 @@ Prioriteta izbire mehanizma je naslednja: Pri uporabi PHPDBG lahko pri obsežnih testih naletite na neuspeh testa zaradi izčrpanja pomnilnika. Zbiranje informacij o pokritosti kode je pomnilniško zahtevno. V tem primeru vam pomaga klic `Tester\CodeCoverage\Collector::flush()` znotraj testa. Zapiše zbrane podatke na disk in sprosti pomnilnik. Če zbiranje podatkov ne poteka ali se uporablja Xdebug, klic nima učinka. -[Primer poročila HTML |https://files.nette.org/tester/coverage.html] s pokritostjo kode. +[Primer poročila HTML |attachment:coverage.html] s pokritostjo kode. --coverage-src .[filter] diff --git a/tester/tr/@meta.texy b/tester/tr/@meta.texy new file mode 100644 index 0000000000..6da801025d --- /dev/null +++ b/tester/tr/@meta.texy @@ -0,0 +1 @@ +{{sitename: Tester Dokümantasyonu}} diff --git a/tester/tr/guide.texy b/tester/tr/guide.texy index c20acc57df..55ad374648 100644 --- a/tester/tr/guide.texy +++ b/tester/tr/guide.texy @@ -152,7 +152,7 @@ Kod Kapsamı Raporları Tester, testlerin ne kadar kaynak kodunu kapsadığına dair genel bir bakış içeren raporlar oluşturabilir. Rapor, ya insan tarafından okunabilir HTML formatında ya da daha fazla makine işleme için Clover XML formatında olabilir. -Kod kapsamıyla ilgili "HTML raporu örneğine":https://files.nette.org/tester/coverage.html bakın. +Kod kapsamıyla ilgili "HTML raporu örneğine":attachment:coverage.html bakın. Desteklenen PHP Sürümleri diff --git a/tester/tr/running-tests.texy b/tester/tr/running-tests.texy index 666fd87567..e0108e3a3a 100644 --- a/tester/tr/running-tests.texy +++ b/tester/tr/running-tests.texy @@ -211,7 +211,7 @@ Mekanizma seçim önceliği şöyledir: PHPDBG kullanırken, kapsamlı testlerde bellek tükenmesi nedeniyle test hatasıyla karşılaşabiliriz. Kod kapsamı bilgilerinin toplanması bellek yoğundur. Bu durumda, test içinde `Tester\CodeCoverage\Collector::flush()` çağrısı yardımcı olur. Bu çağrı, toplanan verileri diske yazar ve belleği serbest bırakır. Veri toplama işlemi gerçekleşmiyorsa veya Xdebug kullanılıyorsa, çağrının hiçbir etkisi olmaz. -Kod kapsamıyla ilgili "HTML raporu örneği":https://files.nette.org/tester/coverage.html. +Kod kapsamıyla ilgili "HTML raporu örneği":attachment:coverage.html. --coverage-src .[filter] diff --git a/tester/uk/@meta.texy b/tester/uk/@meta.texy new file mode 100644 index 0000000000..3c05dc3e34 --- /dev/null +++ b/tester/uk/@meta.texy @@ -0,0 +1 @@ +{{sitename: Документація Tester}} diff --git a/tester/uk/guide.texy b/tester/uk/guide.texy index ff38c2e2bc..8afc8428cd 100644 --- a/tester/uk/guide.texy +++ b/tester/uk/guide.texy @@ -152,7 +152,7 @@ PHP 8.3.2 (cli) | php -n | 8 threads Tester вміє генерувати звіти з оглядом того, скільки вихідного коду покривають тести. Звіт може бути або в людсько-читабельному форматі HTML, або Clover XML для подальшої машинної обробки. -Подивіться на "приклад HTML-звіту":https://files.nette.org/tester/coverage.html з покриттям коду. +Подивіться на "приклад HTML-звіту":attachment:coverage.html з покриттям коду. Підтримувані версії PHP diff --git a/tester/uk/running-tests.texy b/tester/uk/running-tests.texy index 2e3732392b..4e903c15d4 100644 --- a/tester/uk/running-tests.texy +++ b/tester/uk/running-tests.texy @@ -211,7 +211,7 @@ tester tests --coverage coverage.xml # Clover XML звіт При використанні PHPDBG ми можемо зіткнутися з невдачею тесту через вичерпання пам'яті у випадку великих тестів. Збір інформації про покритий код є ресурсомістким за пам'яттю. У цьому випадку нам допоможе виклик `Tester\CodeCoverage\Collector::flush()` всередині тесту. Він запише зібрані дані на диск і звільнить пам'ять. Якщо збір даних не відбувається або використовується Xdebug, виклик не має жодного ефекту. -"Приклад HTML-звіту":https://files.nette.org/tester/coverage.html з покриттям коду. +"Приклад HTML-звіту":attachment:coverage.html з покриттям коду. --coverage-src .[filter] diff --git a/texy/cs/@home.texy b/texy/cs/@home.texy new file mode 100644 index 0000000000..cf88e684e4 --- /dev/null +++ b/texy/cs/@home.texy @@ -0,0 +1,120 @@ +Texy! je sexy! +************** + +.[perex] +Texy je **výkonný a bezpečný markup procesor** pro PHP, který převádí jednoduchý text do validního HTML. Na rozdíl od jiných markup jazyků není Texy jen další variantou Markdown – je to **plně konfigurovatelný systém**, který můžete přizpůsobit prakticky jakékoliv syntaxi. + + +Proč Texy? +========== + + +Bezpečnost na prvním místě +-------------------------- + +Texy je navrženo s důrazem na bezpečnost. Automaticky **chrání před XSS útoky**, validuje URL adresy a filtruje nebezpečné HTML značky. Vestavěný `safeMode()` je ideální pro zpracování uživatelského obsahu v komentářích nebo na fórech. + +```php +Texy\Configurator::safeMode($texy); +// Nyní je Texy bezpečné pro obsah od uživatelů +``` + + +Konfigurovatelnost bez kompromisů +--------------------------------- + +Chcete používat Markdown syntaxi? Nebo potřebujete úplně vlastní markup? **Texy to zvládne.** Můžete: + +- Vypnout nebo zapnout libovolné části syntaxe +- Změnit výchozí chování pomocí handlerů +- Přidat zcela vlastní syntaktické prvky +- Nakonfigurovat Texy tak, aby zpracovávalo Markdown nebo jakýkoliv jiný formát + +```php +$texy = new Texy; +$texy->allowed['image'] = false; // vypnout obrázky +$texy->allowed['phrase/strong'] = false; // vypnout tučné písmo +``` + + +České typografické speciality +----------------------------- + +Texy **dokonale rozumí češtině**. Automaticky: + +- Vkládá **pevné mezery** za jednopísmenné předložky a spojky: v autě, u okna, s kamarádem +- Rozděluje **dlouhá slova** podle slabik: nejneobhospodařovávatelnějšími +- Používá správné **typografické uvozovky**: „dvojité" a ‚jednoduché' +- Zaměňuje **spojovník za pomlčku**: 10–15 vs. česko-slovenský +- Přidává **nezalomitelné mezery** u telefonních čísel: +420 776 552 046 + + +Validní a wellformed HTML +------------------------- + +Texy generuje **vždy validní HTML5 kód**. Automaticky opravuje chybně vnořené značky, uzavírá nezavřené elementy a dbá na správnou strukturu dokumentu. Výstup je nejen validní, ale i **pěkně naformátovaný** s odsazením. + + +Co je Texy? +=========== + +Texy je **obecný procesor markup textu**. To znamená, že má sice svou výchozí syntaxi (podobnou Markdown, ale mnohem bohatší), ale můžete ji kompletně změnit nebo rozšířit. + +**Není to jen parser** – Texy je komplexní systém s modulární architekturou, kde každý modul zpracovává konkrétní část syntaxe (nadpisy, odkazy, obrázky, tabulky...). Díky systému handlerů můžete zasáhnout do libovolného bodu zpracování a změnit výsledek podle svých potřeb. + + +Texy vs. Markdown +================= + +Základní syntaxe je podobná, ale Texy nabízí mnohem více: + +|--------------------------- +| Funkce | Markdown | Texy +|--------------------------- +| Tučné písmo | `**text**` | `**text**` +| Kurzíva | `*text*` nebo `_text_` | `*text*` nebo `//text//` +| Nadpisy | `# Nadpis` | `# Nadpis` nebo podtržení +| Obrázky | `![alt](url)` | `[* url *]` +| Tabulky | omezené | plná podpora včetně sloučení +| Modifikátory | ne | ano – `.{color:red}[class]` +| Typografie | ne | ano – uvozovky, pomlčky, mezery +| Dělení slov | ne | ano – podle slabik +| Konfigurovatelnost | omezená | úplná – vlastní syntaxe +| Bezpečnost | závisí na impl. | vestavěná (safeMode) + +**Příklad rozdílů:** + +```texy +Markdown: +![Obrázek](image.jpg) + +Texy: +[* image.jpg 300x200 .(Popisek obrázku)[photo] <] +``` + +Texy umožňuje definovat rozměry, třídy, zarovnání a mnoho dalšího přímo v syntaxi. + + +Kdy použít Texy? +================ + +Texy je ideální pro: + +**CMS systémy** Potřebujete bezpečně zpracovávat obsah od editorů? Texy nabízí granulární kontrolu nad tím, co mohou uživatelé použít. + +**Blogy a dokumentace** Bohatá syntaxe pro tabulky, obrázky s popiskami, typografii a kód s syntax highlightingem. + +**Komentáře a diskuzní fóra** SafeMode zajistí, že uživatelé nemohou vložit nebezpečný kód, ale zároveň mají k dispozici formátování textu. + +**Projekty s vlastními požadavky** Potřebujete embed YouTube videí? Speciální syntax pro vaše makra? Vlastní markup jazyk? S Texy to vytvoříte snadno. + + +Historie +======== + +Texy vytvořil David Grudl před **20 lety** v roce 2004 jako jeden z prvních markup procesorů pro PHP. Původně bylo vyvinuto pro **PHP 4**, ale během své dlouhé historie prošlo mnoha aktualizacemi a dnes plně využívá všech možností **PHP 8**. + +Přes dvě dekády aktivního vývoje znamenají **vyzkoušenou a stabilní** knihovnu, které důvěřují stovky projektů. Texy je dnes **mature řešení** s velkou historií, ale stále aktivně udržované a moderní. + + +{{maintitle: Texy – formátovač textů pro PHP}} diff --git a/texy/cs/@menu.texy b/texy/cs/@menu.texy new file mode 100644 index 0000000000..bc703bedfb --- /dev/null +++ b/texy/cs/@menu.texy @@ -0,0 +1,7 @@ +- [úvod | @home] +- [syntaxe | syntax] +- [pro programátory | develop] +- "blog .[link-external]":https://phpfashion.com/category/texy +- "hřiště .[link-external]":https://fiddle.nette.org/texy/ +- "API .[link-external]":https://api.nette.org/texy/ +- "GitHub .[link-external]":https://github.com/dg/texy diff --git a/texy/cs/@meta.texy b/texy/cs/@meta.texy new file mode 100644 index 0000000000..41e2da6970 --- /dev/null +++ b/texy/cs/@meta.texy @@ -0,0 +1 @@ +{{sitename: Texy Dokumentace}} diff --git a/texy/cs/architecture.texy b/texy/cs/architecture.texy new file mode 100644 index 0000000000..bf213b08f0 --- /dev/null +++ b/texy/cs/architecture.texy @@ -0,0 +1,425 @@ +Architektura a principy +####################### + +.[perex] +Texy je nástroj pro převod textu napsaného ve vlastním markup jazyce do HTML. Na rozdíl od jednoduchých převodníků, které text zpracovávají lineárně pomocí série náhrad, používá Texy sofistikovaný systém založený na parsování, modulární architektuře a postupném budování DOM stromu. + +Základní tok zpracování probíhá ve čtyřech hlavních fázích: + +1. Předzpracování textu - normalizace, úprava mezer a tabulátorů, volání notification handlerů pro přípravu +2. Parsování - rozpoznání syntaxí pomocí regulárních výrazů a postupné budování DOM stromu +3. Post-processing - typografické úpravy, zpracování dlouhých slov, wellforming HTML +4. Finální sestavení - konverze DOM stromu do HTML řetězce + +Klíčovým rozdílem oproti naivním přístupům je oddělení fáze rozpoznávání syntaxí od jejich zpracování. Parser nejprve identifikuje, kde se v textu nachází která syntaktická konstrukce, a teprve poté předává nalezené části jednotlivým modulům ke zpracování. To umožňuje vnořování syntaxí a jejich postupné rozbalování. + +*Poznámka: všechny třídy se nacházejí ve jmenném prostoru `Texy`, takže pokud dokument zmiňuje například třídu `HtmlElement`, její plný název je `Texy\HtmlElement`. Moduly jsou ve jmenném prostoru `Texy\Modules`* + + +Klíčové komponenty +================== + +Architektura Texy se skládá z několika hlavních komponent, z nichž každá má jasně vymezenou zodpovědnost: + +Třída Texy funguje jako centrální orchestrátor celého systému. Obsahuje odkazy na všechny moduly, spravuje registrované syntaxe a handlery, udržuje stav zpracování a koordinuje jednotlivé fáze konverze. Je to jediné místo, kde se jednotlivé komponenty propojují. + +**[#Moduly]** představují funkční jednotky zodpovědné za konkrétní oblasti markup jazyka. Každý modul při své konstrukci registruje syntaxe, které rozpoznává, a element handlery, které je zpracovávají. Například PhraseModule se stará o inline formátování jako tučný nebo kurzívou psaný text, zatímco TableModule zpracovává tabulky. Moduly jsou navrženy jako samostatné, znovupoužitelné jednotky s vlastní konfigurací přístupnou přes veřejné properties. + +**[#Parsery]** existují ve dvou variantách podle typu zpracovávaného obsahu. BlockParser zpracovává blokové struktury jako odstavce, nadpisy, seznamy nebo tabulky. Prochází text po řádcích, hledá začátky blokových konstrukcí a předává je *syntax handlerům*. LineParser se stará o inline syntaxe uvnitř řádků - odkazy, obrázky, formátování textu. Na rozdíl od BlockParser umožňuje vnořování syntaxí a jejich postupné rozbalování. + + +Základní terminologie +===================== + +Pro správné pochopení fungování Texy je nutné rozlišovat několik klíčových pojmů, které se v dokumentaci často objevují. + +**Syntax** označuje pojmenovanou syntaktickou konstrukci markup jazyka. Každá syntax má jedinečný název, například `phrase/strong` pro tučný text nebo `image` pro obrázky. Název syntaxe se používá pro její zapnutí či vypnutí v poli `Texy::$allowed` a předává se jako parametr do syntax handlerů pro rozlišení, která konkrétní syntax byla nalezena. + +**Pattern** je regulární výraz, který definuje, jak syntax vypadá v textu. Pattern je implementační detail syntaxe - autor syntaxe musí napsat regex, který ji rozpozná, ale z pohledu uživatele Texy je podstatnější název syntaxe a její význam. Jeden modul typicky registruje více syntaxí s různými patterny. + +**Syntax handler** je funkce volaná parserem ve chvíli, kdy najde výskyt syntaxe v textu. Dostává nalezený text a vrací `HtmlElement` nebo řetězec, který se vloží na původní místo. Syntax handler je místem, kde se rozhoduje, co se s nalezenou syntaxí stane - typicky vyvolá element handler pro vlastní zpracování. + +**Element** je prvek, pro který se generuje HTML reprezentace. Například `image` je element pro obrázky, `linkURL` pro odkazy, `phrase` pro inline formátování. Každý element má svůj výchozí element handler, který se stará o standardní zpracování. + +**Element handler** je funkce registrovaná pro určitý typ prvků a volaná přes systém HandlerInvocation. Charakteristické je použití metody `proceed()`, která umožňuje delegovat zpracování na další handler v řetězu nebo na výchozí handler modulu. Element handlery slouží k modifikaci nebo nahrazení výchozího chování. + +**Notification handler** je funkce volaná pro notifikaci o určité události. Na rozdíl od element handlerů nevrací žádnou hodnotu a nemůže ovlivnit výsledek zpracování. Používá se pro přípravu dat, logování nebo modifikace již vytvořeného DOM stromu. + +Rozdíl mezi jednotlivými handlery je klíčový pro pochopení architektury. Syntax handler je těsně svázán s parserem a konkrétním patternem - řeší otázku *co dělat, když parser najde tento pattern*. Element handlery jsou na vyšší úrovni abstrakce - řeší otázku *jak zpracovat tento typ prvku*, bez ohledu na to, která konkrétní syntax ji vytvořila. + + +Celkový tok zpracování +====================== + +Když Texy dostane vstupní text, projde následujícím procesem zpracování. + +V předzpracování dochází k normalizaci textu. Koncové značky řádků se sjednotí na Unix formát, mezery se standardizují a tabulátory se případně nahradí mezerami. Následně se vyvolají *notification handlery* registrované pro událost `beforeParse`. Tyto handlery mohou provést přípravu dat, například načíst definice referencí nebo upravit konfiguraci podle obsahu textu. + +Samotné parsování začíná vytvořením kořenového `HtmlElement`, který reprezentuje dokument. Texy pak rozhodne, zda text zpracovat jako jeden řádek nebo jako kompletní dokument s blokovými strukturami. V případě blokového zpracování se vytvoří BlockParser, který postupně prochází text a hledá jednotlivé blokové konstrukce. + +LineParser pracuje jinak než BlockParser. Neprochází text lineárně, ale postupně hledá nejbližší výskyt jakékoliv registrované syntaxe. Když nějakou najde, zavolá příslušný syntax handler, který vytvoří odpovídající HTML element. Tento element se pomocí speciálního maskování vloží zpět do textu a parser pokračuje dál. Díky tomu může najít a zpracovat syntaxe vnořené uvnitř již zpracovaných konstrukcí. + +Po dokončení parsování vznikne kompletní DOM strom reprezentující strukturu dokumentu. Texy vyvolá notification handlery pro událost `afterParse`, které mohou provést závěrečné úpravy stromu, například doplnit identifikátory nadpisů nebo sestavit obsah. + +Post-processing probíhá během konverze DOM stromu na HTML řetězec. Každý element se rekurzivně převádí na HTML kód, přičemž se aplikují typografické úpravy jako nahrazení uvozovek, pomlček nebo vkládání nezlomitelných mezer. Dále se provádí wellforming HTML - automatické uzavírání tagů, oprava špatně vnořených elementů, formátování a odsazování kódu. + +Finální fází je dekódování všech maskovaných částí zpět na HTML tagy, odstranění pomocných značek a sestavení výsledného HTML řetězce. + + +Systém syntaxí +************** + +Syntax v terminologii Texy představuje pojmenovanou syntaktickou konstrukci markup jazyka. Je to abstraktní koncept spojující několik prvků: unikátní název, regulární výraz pro rozpoznání a způsob zpracování. Název syntaxe slouží jako identifikátor v celém systému - používá se v poli `Texy::$allowed` pro zapnutí či vypnutí, předává se do handlerů pro rozlišení typu konstrukce a objevuje se v dokumentaci a konfiguračních souborech. + +Jmenné konvence syntaxí následují dva hlavní vzory. Jednodušší syntaxe mají jednoslovný název odpovídající jejich účelu, například `image`, `table` nebo `script`. Složitější oblasti používají hierarchické pojmenování se lomítkem, například `phrase/strong`, `phrase/em` nebo `link/reference`. Lomítko slouží k logickému seskupení souvisejících syntaxí a usnadňuje hromadné operace s nimi. + + +Line syntaxe +============ + +Line syntaxe slouží k rozpoznávání inline prvků uvnitř řádků textu. Typicky jde o formátování jako tučný nebo kurzívou psaný text, odkazy, obrázky nebo inline kód. Charakteristické pro line syntaxe je, že mohou být vnořené do sebe a parser je postupně rozbaluje. + +Registrace line syntaxe probíhá voláním `Texy::registerLinePattern()` s několika parametry. První je syntax handler, tedy callback volaný při nálezu. Druhý parametr je regulární výraz definující podobu syntaxe v textu. Třetí parametr je název syntaxe používaný v celém systému. Volitelný čtvrtý parametr je další regex pro test, zda má smysl pattern vůbec hledat - používá se pro optimalizaci, aby se nespouštěl komplexní pattern na textu, který určitě nemůže matchnout. + +Pattern jako regulární výraz musí splňovat určitá pravidla. Nesmí být kotvený na začátek textu, protože se hledá kdekoliv v řádku. Měl by být co nejkonkrétnější, aby nedošlo k falešným matchům. + +Inline syntaxe uvnitř řádků textu zpracovává [#LineParser]. Když najde match, zavolá příslušný syntax handler. Ten dostává tři parametry. První je instance LineParser, která poskytuje přístup k Texy objektu a dalším informacím o kontextu. Druhý parametr je pole s výsledky regex matche včetně podvýrazů. Třetí parametr je název syntaxe, který je užitečný, když stejný callback obsluhuje více syntaxí. Handler musí vrátit buď `HtmlElement`, nebo řetězec, nebo null pokud zpracování odmítá. + + +Block syntaxe +============= + +Block syntaxe rozpoznávají víceřádkové blokové konstrukce jako nadpisy, seznamy, tabulky, citace nebo speciální bloky. Na rozdíl od line syntaxí se block syntaxe nikdy nepřekrývají - každý řádek textu patří maximálně do jedné blokové konstrukce. + +Registrace block syntaxe používá `Texy::registerBlockPattern()` se třemi parametry. Syntax handler, regulární výraz a název syntaxe. Pattern jako regulární výraz musí splňovat určitá pravidla. Musí matchnout od začátku řádku a často obsahuje kotvu pro konec řádku. BlockParser automaticky přidává modifikátory Am, takže pattern by je neměl obsahovat. + +Block syntaxe uvnitř dokumentu zpracovává [#BlockParser]. Když najde match, zavolá příslušný syntax handler. Ten dostává podobné parametry jako u line syntaxí - BlockParser instanci, pole s matchem a název syntaxe. Vrací `HtmlElement` reprezentující celý zpracovaný blok, nebo null při odmítnutí zpracování. + + +Zapnutí a vypnutí syntaxe +========================= + +Pole `Texy::$allowed` poskytuje jemně granulární kontrolu nad tím, které syntaxe jsou v Texy aktivní. Je to jednoduchý, ale mocný mechanismus pro konfiguraci chování bez nutnosti měnit kód modulů. Když zakážete syntaxi `phrase/strong` tímto nastavením, parser přestane hledat konstrukci tučného textu: + +```php +$texy->allowed['phrase/strong'] = false; +``` + +Kontrola probíhá jednou při začátku parsování, takže dynamická změna `$allowed` během zpracování nemá efekt. + +Při konstrukci modulů se pro většinu syntaxí nastavuje výchozí hodnota `$allowed`. Některé syntaxe jsou ve výchozím stavu zapnuté, protože tvoří základ markup jazyka. Jiné jsou vypnuté, protože jsou pokročilé nebo potenciálně nebezpečné. Například emotikony jsou vypnuté, protože ne každý dokument je potřebuje, zatímco základní formátování je zapnuté. + +Bezpečný režim je situace, kdy zpracováváte nedůvěryhodný vstup, například komentáře od uživatelů. Chcete povolit základní formátování, ale zakázat obrázky, skripty nebo HTML tagy. `Texy\Configurator::safeMode()` nastaví `$allowed` pro bezpečnou kombinaci syntaxí. Typicky zakáže image, figure, script a HTML tagy, ale ponechá odkazy a formátování. + + +Parsery +******* + + +Syntax handler +============== + +Jak jsme si říkali v předchozí části, LineParser nebo BlockParser prochází text a hledají všechny registrované patterny. Když najde match, zavolá příslušný syntax handler a předá mu informace o nálezu - zejména pole s výsledky regex matche. + +Syntax handler analyzuje nalezený text a připravuje data pro zpracování. Může extrahovat části textu z regex skupin, vytvořit pomocné objekty jako `Link` nebo `Image`, parsovat modifikátory. Rozhoduje také, jaký element handler vyvolat. Zavolá `Texy::invokeAroundHandlers()` s názvem elementu a připravenými parametry. Tím začne jejich vykonávání. Vrácený výsledek se dostává zpět do syntax handleru, který ho vrátí parseru. + + +Element handler +=============== + +Element handlery implementují vzor chain of responsibility, který umožňuje složit výsledné chování z více vrstev. + +Registrace element handleru probíhá voláním `Texy::addHandler()` se dvěma parametry - názvem elementu a funkcí handleru. Jeden název elementu může mít zaregistrováno více handlerů, které se pak vykonávají v pořadí od posledně registrovaného k prvnímu. + +Název elementu identifikuje, o jaký typ zpracování jde, například `phrase` pro formátování, `image` pro obrázky nebo `link` pro odkazy (pozor: jde o něco jiného než názvy syntaxe). Někdy se používají složené názvy jako `linkReference` nebo `linkEmail` pro rozlišení různých druhů odkazů. Názvy jsou obecnější než názvy syntaxí - zatímco syntaxe `phrase/strong` je specifická konstrukce, element `phrase` pokrývá všechny druhy inline formátování. + +Vyvolání element handleru používá metodu `Texy::invokeAroundHandlers()`. Tato metoda dostává název prvku, instanci parseru a pole parametrů. Vytvoří HandlerInvocation objekt, který zapouzdřuje celý řetěz zaregistrovaných handlerů. První handler v řetězu dostane kontrolu a rozhoduje, zda zavolat `HandlerInvocation::proceed()` pro pokračování na další handler, nebo vrátit vlastní výsledek. + +HandlerInvocation objekt je klíčem k pochopení, jak řetězení funguje. Obsahuje zásobník všech handlerů pro daný prvek a aktuální pozici v tomto zásobníku. Když handler zavolá `proceed()`, HandlerInvocation posune pozici o jedno místo zpět v zásobníku a zavolá další handler. Pokud handler zavolá `proceed()` s modifikovanými parametry, tyto nové parametry se předají všem následujícím handlerům. Pokud handler vůbec nezavolá `proceed()`, řetěz se přeruší a jeho návratová hodnota se stane výsledkem celého zpracování. + +Pořadí vykonávání handlerů je od posledně zaregistrovaného k prvnímu. To znamená, že uživatelský handler zaregistrovaný dodatečně dostane kontrolu první a může rozhodnout, zda vůbec zavolá výchozí handler modulu. Toto pořadí umožňuje uživatelům přepsat výchozí chování bez nutnosti měnit kód modulu. + +Typické použití element handleru vypadá následovně. Handler zkontroluje vstupní parametry a rozhodne, zda chce zasáhnout do zpracování. Pokud ano, upraví data, zavolá `proceed()` s novými parametry a případně ještě upraví vrácený výsledek. Pokud chce handler úplně nahradit výchozí zpracování, vytvoří vlastní výsledek a vrátí ho bez volání `proceed()`. + + +Notification handler +==================== + +Notification handlery představují jednodušší, jednosměrný komunikační mechanismus. Na rozdíl od element handlerů neslouží k transformaci dat, ale k provedení vedlejších akcí. + +Registrace notification handleru používá stejnou metodu `Texy::addHandler()` jako element handlery. Rozdíl je v tom, jak se handler používá - notification handler nevrací žádnou hodnotu a nemá přístup k HandlerInvocation. První parametr je název události. Používají se popisné názvy jako `beforeParse` a `afterParse` pro globální události okolo parsování, nebo specifičtější jako `afterTable`, `afterList`, `afterBlockquote` pro události po vytvoření konkrétní struktury. Prefix before/after jasně indikuje časování události. + +Vyvolání notification handlerů používá metodu `Texy::invokeHandlers()`. Tato metoda jednoduše zavolá všechny zaregistrované handlery v pořadí a ignoruje jejich návratové hodnoty. Notification handlery dostanou parametry předané při vyvolání, ale nemohou je měnit pro další handlery v řadě. + +Typické použití notification handlerů zahrnuje několik scénářů. Handler pro událost `beforeParse` může načíst definice referencí z textu ještě před začátkem parsování. Handler `afterParse` může projít vytvořený DOM strom a doplnit chybějící atributy nebo sestavit tabulku obsahu. Handlery jako `afterTable` nebo `afterList` umožňují modulům provést závěrečné úpravy vytvořených struktur. + +Důležitý rozdíl oproti element handlerům je v tom, že notification handlery nemohou zabránit dalšímu zpracování. Všechny zaregistrované handlery se vždy vykonají, žádný nemůže přerušit řetěz. To je zamýšlené chování - notification handlery jsou o vedlejších efektech, ne o kontrole toku. + + +LineParser +========== + +LineParser zpracovává inline syntaxe uvnitř řádků textu postupným způsobem, který umožňuje vnořování a složité interakce mezi syntaxemi. + +Základní princip spočívá v hledání prvního výskytu jakékoliv syntaxe. V každé iteraci projde všechny syntaxe a zjistí, která z nich matchuje nejblíže aktuální pozici v textu. Tato syntax *vyhrává* a zpracuje se. Pokud více syntaxí matchuje na stejné pozici, vyhrává ta, která byla registrována dříve - to je priorita podle pořadí registrace. + +Když parser najde nejbližší match, zavolá příslušný syntax handler. Ten vrátí výsledek, který může být `HtmlElement` nebo řetězec. A tímto výsledkem se přepíše nalezený match v textu. + +Poté hledá znovu od aktuální pozice. Tento systém zajišťuje, že parser vždy vidí aktuální stav textu. Když nahradíme match novým textem, který může obsahovat další syntaxe, tyto syntaxe se najdou v příští iteraci. + +Property `$again` na LineParser objektu slouží k jemnému řízení toho, zda by se měla právě matchnutá syntaxe hledat znovu na stejné pozici po zpracování aktuálního matche. Výchozí hodnota je false, která říká: *Na této pozici už nemá smysl hledat tuto stejnou syntaxi. Posuň se dál.* + +Průchod končí, když parser dojde na konec textu nebo když už žádná syntaxe nemá další match. Výsledkem je text, kde všechny rozpoznatelné syntaxe byly zpracovány a nahrazeny výsledky, připravený pro finální konverzi. + + +Vnořování +--------- + +Schopnost zpracovat vnořené syntaxe je jednou z klíčových vlastností LineParser a představuje základní výzvu - jak zabránit tomu, aby již zpracované HTML tagy byly omylem interpretovány jako další syntax k zpracování. + +Když parser zpracovává text obsahující vnořené syntaxe, nejprve najde vnější konstrukci. Například v textu `"odkaz **tučný** text":URL` parser nejprve najde syntaxi pro odkaz s uvozovkami. Pattern pro tuto syntaxi matchuje celý řetězec od první uvozovky po dvojtečku a URL. Syntax handler vytvoří `HtmlElement` pro tag `` a obsah `odkaz **tučný** text` se přidá jako potomek elementu. Tento řetězec vloží zpět do textu a pokračuje v hledání dalších syntaxí (`**tučný**`, který představuje tučný text). + +Ale teď má problém - v textu jsou také HTML značky, která může matchnout jako začátek jiné syntaxe. Parser by začal zpracovávat již hotové HTML tagy jako kdyby byly část původního textu. + +Nechceme, aby parser viděl HTML tagy. Potřebujeme nějaký způsob, jak rozlišit již zpracované části od částí čekajících na zpracování. Metoda `Texy::protect()` řeší tyto problémy elegantním způsobem - nahradí HTML tagy unikátním placeholderem složeným z control characters - speciálních bytů mimo tisknutelné ASCII. + +Když se tedy `HtmlElement` převádí na řetězec (pomocí `toString()`), výsledek nevypadá jako `odkaz **tučný** text`, ale například jako `\x17\x18\x19\x17odkaz **tučný** text\x17\x18\x1A\x17`. + +V textu během parsování tak nejsou nikdy přítomny skutečné HTML tagy. Místo nich jsou pouze placeholdery. Ale vnitřní text zůstává a parser ho normálně vidí a může v něm hledat další syntaxe. To umožňuje postupné vnořování - vnější syntax se zamaskuje, ale její obsah je stále přístupný pro vnitřní syntaxe. + +Na konci zpracování metoda `Texy::unProtect()` projde výsledný HTML řetězec a nahradí všechny placeholdery jejich skutečnými hodnotami. Teprve v tomto okamžiku se do výstupu dostanou skutečné HTML tagy. + + +Úrovně maskování +---------------- + +Různé druhy obsahu používají různé control characters pro své placeholdery, což umožňuje syntaxím selektivně rozhodnout, co mohou obsahovat. + +- `Patterns::CONTENT_MARKUP` označuje běžný HTML markup jako tagy pro formátování nebo odkazy. Je to nejběžnější typ a používá ho většina inline elementů. Placeholder začíná a končí `\x17`. +- `Patterns::CONTENT_REPLACED` označuje obsah, který byl nahrazen něčím jiným, typicky obrázky nebo jiné replaced elementy. Používá `\x16` jako marker. +- `Patterns::CONTENT_TEXTUAL` označuje text, který byl escapován nebo jinak ošetřen, aby se nezpracovával. Používá se pro konstrukce jako code nebo notexy, kde chceme zobrazit původní text včetně markup symbolů, ne jejich interpretaci. +- `Patterns::CONTENT_BLOCK` označuje blokové elementy. Je to nejnižší úroveň v hierarchii. Používá `\x14` jako marker. + +Hierarchie těchto typů není jen konvence, ale má praktický důsledek. Konstantní Patterns::MARK je definována jako `\x14-\x1F`, tedy rozsah pokrývající všechny tyto typy plus rezervu. Syntaxe používají tuto konstantu ve svých patterns pro vyloučení maskovaných částí. + +Různé syntaxe mohou mít různé požadavky na to, co mohou obsahovat za placeholdery. Pattern, který chce vidět pouze čistý text bez jakýchkoliv maskovaných částí, použije vyloučení `[^\x14-\x1F]`. To odmítne všechny placeholdery všech typů. Příkladem je pattern pro obrázky - URL obrázku by neměla obsahovat žádné HTML tagy ani bloky. + +Pattern, který akceptuje nižší úrovně, ale odmítá vyšší, použije užší rozsah. Například `[^\x17-\x1F]` odmítne pouze `CONTENT_MARKUP` a výš, ale akceptuje `CONTENT_BLOCK`, `CONTENT_TEXTUAL` a `CONTENT_REPLACED`. To je užitečné, pokud chceme povolit bloky, ale ne inline markup. Praktickým příkladem je TypographyModule, který provádí typografické úpravy jako nahrazení uvozovek nebo vkládání nezlomitelných mezer. Tyto úpravy by se měly aplikovat na běžný text, ale ne uvnitř bloků kódu nebo preformátovaného textu. + + +Kolize syntaxí +-------------- + +Kolize nastává, když více syntaxí může matchnout na stejné pozici, a systém musí vybrat jednu z nich. + +Typickým příkladem jsou různé délky stejného symbolu. Syntaxe `phrase/strong+em` používá tři hvězdičky pro kombinaci tučného a kurzívy. Syntaxe `phrase/strong` používá dvě hvězdičky pro samotný tučný text. Syntaxe `phrase/em-alt` používá jednu hvězdičku pro kurzívu. Když parser najde text začínající třemi hvězdičkami, všechny tři syntaxe technicky mohou matchnout. + +PhraseModule řeší tuto kolizi registrací syntaxí v pořadí od nejdelší po nejkratší. Nejprve registruje `phrase/strong+em` s patternem pro tři hvězdičky. Pak `phrase/strong` s patternem pro dvě hvězdičky. Nakonec `phrase/em-alt` s patternem pro jednu hvězdičku. Díky tomuto pořadí se při nálezu tří hvězdiček zpracuje nejprve `phrase/strong+em` a kratší syntaxe nedostanou šanci. + +Další příklad jsou odkazy v různých formátech. Syntaxe `phrase/wikilink` používá pattern pro `[text|url]`. Syntaxe `link/reference` používá pattern pro `[ref]`. Oba začínají otevírací hranatou závorkou. Pokud je v textu `[text|url]`, oba patterns technicky mohou začít matchnout. + +Řešením je opět specifičnost patterns. Pattern pro `phrase/wikilink` je specifičtější - vyžaduje svislítko uvnitř závorek. Pokud text obsahuje svislítko, matchne `phrase/wikilink`. Pokud ne, pattern selže a `link/reference` má šanci. Pořadí registrace zde také hraje roli - `phrase/wikilink` by měla být registrována dříve než `link/reference`. + + +BlockParser +=========== + +BlockParser používá fundamentálně odlišný přístup k zpracování, který reflektuje povahu blokových konstrukcí. Základní rozdíl je v absenci prolínání. Zatímco LineParser umožňuje, aby syntaxe byly vnořené do sebe a postupně se rozbalovaly, BlockParser pracuje s předpokladem, že každý blok je samostatná jednotka. Jeden řádek nebo skupina řádků patří k maximálně jednomu bloku. Bloky se nepřekrývají, nekříží a nevnoří na úrovni BlockParser. + +BlockParser začíná vyhledáním všech bloků, respektive jejich začátků. Parser projde všechny registrované block syntaxe a najde všechny jejich výskyty. Pokud více syntaxí matchuje na stejné pozici, použije se pořadí registrace - dříve registrovaná syntaxe má přednost. + + +API pro syntax handler +---------------------- + +BlockParser poskytuje syntax handlerům API pro práci s víceřádkovými strukturami. + +Metoda `BlockParser::moveBackward()` slouží k návratu na předchozí řádky. Přijímá počet řádků, o které se má vrátit. Parser posune svou interní pozici směrem k začátku textu, dokud nepřejde přes specifikovaný počet konců řádků. To umožňuje callbacku začít číst od začátku struktury, i když pattern matchnul až uprostřed nebo na konci. + +Metoda `BlockParser::next()` slouží k čtení dalšího řádku odpovídajícího určitému patternu. Přijímá regex pattern (automaticky přidá modifikátory `Am`) a referenci na proměnnou pro výsledek matche. Pokud další řádek v textu matchuje poskytnutý pattern, metoda naplní výsledek, posune interní pozici za tento řádek a vrátí true. Pokud další řádek nematchuje, metoda vrátí false a pozice se nezmění. + + +Moduly +****** + +Moduly jsou základní organizační jednotkou v architektuře Texy. Každý modul zapouzdřuje kompletní funkcionalitu pro určitou oblast markup jazyka. + +Primární zodpovědností modulu je registrace syntaxí. V konstruktoru modul volá `Texy::registerLinePattern()` nebo `registerBlockPattern()` pro všechny syntaxe, které chce zpracovávat. Tím říká parseru: *Když najdeš tyto patterny, zavolej mě.* Modul tak definuje, které konstrukce v textu rozpoznává. + +Druhá zodpovědnost je implementace element handlerů. Modul registruje handlery pro elementy, které jeho syntaxe vyvolávají. Tyto handlery obsahují logiku pro převod nalezených konstrukcí na HTML elementy. Element handler rozhoduje, jaký element vytvořit, jaké atributy nastavit a jak zpracovat obsah. + +Třetí zodpovědnost je poskytnutí konfigurace. Moduly mají veřejné properties, které umožňují uživatelům Texy upravit chování modulu bez nutnosti měnit jeho kód. Například ImageModule má properties pro nastavení root cesty k obrázkům nebo výchozího alt textu. + +Čtvrtá zodpovědnost je správa stavu specifického pro modul. Například HeadingModule sleduje všechny nalezené nadpisy v poli TOC pro sestavení obsahu. LinkModule spravuje slovník referencí pro odkazy. Tento stav je soukromý pro modul a ostatní části systému k němu nepřistupují přímo. + +Moduly jsou navrženy jako nezávislé jednotky. Každý modul může fungovat samostatně a neměl by záviset na implementačních detailech jiných modulů. Komunikace mezi moduly probíhá přes sdílené objekty jako `Link` nebo `Image`, ne přes přímé volání metod. + + +Struktura typického modulu +========================== + +Většina modulů v Texy následuje podobnou strukturu, která reflektuje jejich úlohu v systému. + +Modul dědí od základní třídy Module, která poskytuje přístup k Texy objektu přes protected property `$texy`. Konstruktor modulu přijímá instanci Texy a uloží si ji. To umožňuje modulu přistupovat ke konfiguraci a volat metody na Texy objektu. + +V konstruktoru probíhá veškerá inicializace. Modul nastaví výchozí hodnoty konfiguračních properties, případně nastaví výchozí hodnoty v poli `Texy::$allowed` pro své syntaxe. Pak registruje své syntaxe voláním `registerLinePattern()` nebo `registerBlockPattern()`. Každá registrace spojuje pattern, syntax handler a název syntaxe. Nakonec modul registruje své element handlery voláním `addHandler()`. + +Syntax handlery jsou metody modulu, které parser volá při nálezu syntaxe. Tyto metody typicky extrahují části z regex matche, vytvářejí pomocné objekty a vyvolávají element handlery. Syntax handler rozhoduje, jaký element handler vyvolat a jaké parametry předat. + +Element handlery jsou metody implementující skutečné zpracování. Dostávají HandlerInvocation objekt jako první parametr, následovaný parametry specifickými pro daný element. Element handler vytváří `HtmlElement`, aplikuje modifikátory, zpracovává obsah a vrací výsledek. Je to místo, kde se rozhoduje o finální podobě HTML. + +Veřejné properties slouží jako rozhraní pro konfiguraci. Uživatel Texy může nastavit tyto properties pro přizpůsobení chování modulu. Properties jsou typicky primitivní typy nebo pole, ne složité objekty, aby konfigurace byla jednoduchá. + + +Přehled klíčových modulů +======================== + +Standardní distribuce Texy obsahuje několik modulů pokrývajících různé aspekty markup jazyka. + +- **PhraseModule** zpracovává inline formátování textu. Registruje syntaxe pro tučný text, kurzívu, podtržení, horní a dolní index, kód a další. Všechny tyto syntaxe vyvolávají společný handler pro element `phrase` a handler rozlišuje podle názvu syntaxe, jaký tag vytvořit. Modul umožňuje konfigurovat, které tagy se použijí pro jednotlivé druhy formátování. + +- **LinkModule** spravuje odkazy v dokumentu. Registruje syntaxe pro různé formáty odkazů - explicitní URL, emailové adresy, reference na definované odkazy. Poskytuje factory metody pro vytváření `Link` objektů a spravuje slovník referencí. Modul umožňuje konfigurovat root pro relativní odkazy, automatické `rel="nofollow"` pro externí odkazy a zkracování dlouhých URL. + +- **ImageModule** zpracovává obrázky podobným způsobem jako LinkModule odkazy. Registruje syntaxi pro inline obrázky a spravuje slovník referencí na definované obrázky. Poskytuje factory metody pro vytváření `Image` objektů a automatickou detekci rozměrů obrázků. Konfigurovatelné jsou cesty k obrázkům, výchozí alt text a CSS třídy pro zarovnání. + +- **HeadingModule** rozpoznává nadpisy v různých formátech - podtržené pomlčkami nebo rovnítky, obklopené mřížkami. Shromažďuje všechny nadpisy do pole TOC pro možné sestavení obsahu. Umožňuje konfigurovat generování ID, top úroveň nadpisů a režim balancování úrovní. + +- **ListModule** zpracovává seznamy - nečíslované, číslované a definiční. Rozpoznává různé typy odrážek a automaticky detekuje vnořování podle odsazení. Umožňuje konfigurovat, které znaky slouží jako odrážky a jaké HTML listy generovat. + +- **TableModule** je jedním z nejkomplexnějších modulů. Rozpoznává tabulky s hlavičkami, těly, titulky a podporuje colspan a rowspan. Zpracovává modifikátory pro řádky i buňky. + +- **BlockModule** zpracovává speciální bloky ohraničené `/--` a `\--`. Podporuje různé typy bloků - code pro kód, html pro přímé HTML, div pro generický kontejner. Umožňuje uživatelům definovat vlastní handlery pro vlastní typy bloků. + +- **TypographyModule** provádí post-processing pro typografické úpravy. Nahrazuje tři tečky elipsou, dvojité pomlčky en-dash, přímé uvozovky typografickými a vkládá nezlomitelné mezery. Pracuje na úrovni finálního řetězce mezi blokovými elementy. + +- **HtmlOutputModule** formátuje finální HTML výstup. Zajišťuje wellformed HTML automatickým zavíráním tagů, opravou nesprávného vnořování, odsazením kódu a zalamováním dlouhých řádků. Umožňuje konfigurovat úroveň odsazení a šířku řádků. + + +Interakce mezi moduly +===================== + +Ačkoliv jsou moduly navrženy jako nezávislé, v některých případech musí spolupracovat. + +Sdílené objekty jsou hlavní mechanismus komunikace. `Link` objekt vytvořený LinkModule může být předán ImageModule pro vytvoření obrázkového odkazu. `Image` objekt vytvořený ImageModule může být předán FigureModule pro vytvoření obrázku s popiskem. Tyto objekty zapouzdřují veškeré potřebné informace a poskytují společné rozhraní. + +Reference systém umožňuje oddělit definici od použití. LinkModule poskytuje metody `addReference()` a `getReference()` pro správu slovníku pojmenovaných odkazů. Uživatel může v jedné části dokumentu definovat referenci a v jiné ji použít. ImageModule má analogický systém pro reference na obrázky. Moduly používající reference volají factory metody, které samy kontrolují, zda jde o referenci nebo přímou hodnotu. + +Element handlers mohou volat jiné element handlery. PhraseModule při zpracování `phrase/span` s odkazem vytvoří `Link` objekt a zavolá element handler LinkModule pro vytvoření odkazu. Tím deleguje odpovědnost za vytvoření a konfiguraci odkazu na specializovaný modul. + +Vztahy mezi moduly jsou typicky jednostranné. PhraseModule zná LinkModule a ImageModule, protože vytváří odkazy a obrázky. Ale LinkModule a ImageModule neznají PhraseModule. To udržuje závislosti jednoduché a umožňuje snadné nahrazení nebo rozšíření modulů. + + +DOM reprezentace +**************** + +`HtmlElement` reprezentuje jeden uzel v DOM stromu a poskytuje rozhraní pro jeho manipulaci a zpracování. + +Základní struktura elementu obsahuje název tagu, asociativní pole atributů a pole potomků. Potomci mohou být další instance `HtmlElement` nebo prostě textové řetězce. Tato kombinace umožňuje reprezentovat libovolnou HTML strukturu. + +Název elementu se nastavuje a získává přes metody `setName()` a `getName()`. Speciální hodnota null jako název znamená transparentní element, který nemá tagy, jen jeho obsah. + +Atributy jsou veřejně přístupné přes property `$attrs` jako asociativní pole. Hodnoty mohou být řetězce, čísla, boolean nebo pole. Boolean true znamená atribut bez hodnoty (jako checked), false nebo null znamená atribut se vůbec nevykreslí. Pokud je hodnota pole, různé prvky se spojí podle typu atributu - pro class mezerami, pro style středníky. Metoda `setAttribute()` nastaví hodnotu atributu. Metoda `getAttribute()` vrací hodnotu atributu nebo null. + +Potomci se spravují přes několik metod. Metoda `add()` přidává potomka na konec. Metoda `insert()` vkládá potomka na specifikovanou pozici, volitelně nahrazuje existujícího potomka. Metoda `create()` vytváří nový `HtmlElement` jako potomka a vrací ho pro další manipulaci. Metoda `removeChildren()` odstraní všechny potomky. + +Element implementuje ArrayAccess interface, takže s potomky lze pracovat jako s polem. Zápis `$el[0]` vrací prvního potomka, `$el[0] = $child` nastaví prvního potomka. Tento přístup je pohodlný pro rychlou manipulaci s konkrétními potomky. + +Metoda `toString()` prochází element a jeho potomky rekurzivně a sestavuje řetězcovou reprezentaci. HTML tagy se okamžitě zamaskují pomocí `Texy::protect()`, takže do výsledku jde placeholder místo skutečných HTML znaků. + +Metody `toHtml()` a `toText()` vrací výsledek nemaskovaný včetně post-processingu. + + +Parsování obsahu +================ + +`HtmlElement` může rekurzivně parsovat svůj obsah, čímž umožňuje postupné budování DOM stromu. + +Metoda `parseLine()` slouží k parsování inline syntaxí v řetězci. Vytvoří novou instanci LineParser s aktuálním elementem jako kontejnerem. Zavolá `parse()` na parseru s poskytnutým textem. LineParser postupně najde a zpracuje všechny inline syntaxe a výsledné elementy nebo řetězce přidá jako potomky aktuálního elementu. Metoda vrací použitý LineParser pro případné další použití. + +Metoda `parseBlock()` parsuje text jako blokový obsah. Vytvoří BlockParser a zavolá na něm `parse()`. BlockParser najde všechny blokové konstrukce v textu, zpracuje je a přidá jako potomky elementu. Text mezi bloky se zpracuje jako odstavce, které interně používají LineParser. Metoda přijímá boolean parametr indikující, zda text pochází z odsazeného bloku, což ovlivňuje zpracování odstavců. + +Tyto parsovací metody umožňují rekurzivní zpracování. Syntax handler může vytvořit element, nastavit jeho základní vlastnosti a pak zavolat `parseLine()` nebo `parseBlock()` pro zpracování obsahu. Výsledkem je, že obsah elementu prochází stejným procesem parsování jako hlavní dokument, včetně rozpoznávání syntaxí a vyvolávání handlerů. + + +Validace +======== + +`HtmlElement` poskytuje mechanismy pro validaci atributů a obsahu podle HTML DTD (Document Type Definition). + +DTD je statické pole definující pro každý HTML tag, které atributy jsou povolené a jaký obsah může obsahovat. Texy načítá DTD ze souboru při inicializaci a uloží ho do statického pole. Struktura DTD mapuje název tagu na dvojici - pole povolených atributů a pole povoleného obsahu. + +Metoda `validateAttrs()` kontroluje atributy elementu podle DTD. Pro daný tag získá seznam povolených atributů. Prochází všechny atributy elementu a ty, které nejsou v seznamu, odstraní. Speciální případy jsou atributy začínající data- nebo aria-, které jsou povolené, pokud je v DTD zástupný záznam `data-*` nebo `aria-*`. + +Tato validace se typicky volá při aplikaci modifikátorů metodou `decorate()`. Zajišťuje, že i když uživatel zadá modifikátor s neplatným atributem pro daný tag, atribut se do finálního HTML nedostane. To je důležité pro bezpečnost a správnost HTML. + +Metoda `validateChild()` kontroluje, zda daný potomek může být obsahem elementu. Přijímá potomka (`HtmlElement` nebo název tagu) a DTD. Pokud je element v DTD definován, metoda zkontroluje, zda potomek je v seznamu povoleného obsahu. Pokud ano, vrací true. Pokud ne, vrací false. + +Tato validace se může použít při dynamickém sestavování DOM stromu pro zajištění korektní struktury. Například paragraph element nesmí obsahovat blokové elementy, takže `validateChild()` by odmítlo přidat div do p. V praxi Texy tuto validaci používá omezeně, protože struktura generovaná moduly je typicky správná by design. + +Kombinace `validateAttrs()` a `validateChild()` poskytuje mechanismus pro zajištění validního HTML, i když vstup obsahuje nedůvěryhodná data nebo špatně formované konstrukce. Texy může být nakonfigurováno pro striktní validaci nebo může validaci vypnout pro maximální flexibilitu. + + +Modifikátory +************ + +Modifikátory poskytují způsob, jak přidat elementům dodatečné atributy, třídy, styly a zarovnání bez nutnosti psát přímé HTML. + +Základní formát modifikátoru je tečka následovaná kombinací různých částí v kulatých, hranatých a složených závorkách: `.(title)[class1 class2 #id]{style:value}^valign`. Celý modifikátor se píše před nebo na konec konstrukce, na kterou se aplikuje. Například `"**text** .(Důležité)[highlight]{color:red}"` vytvoří tučný text se třídou highlight, červenou barvou a title atributem Důležité. + +Kulaté závorky obsahují title atribut nebo alt text. Text uvnitř se použije jako hodnota title atributu na výsledném elementu. Pokud element je obrázek, může se použít jako alt text. Uvnitř kulatých závorek je možné escapovat závorku zpětným lomítkem. + +Hranaté závorky obsahují CSS třídy a volitelně ID. Třídy se píší jako slova oddělená mezerami. ID se píše s prefixem mřížky. Například `[main-content selected #article-5]` nastaví dvě třídy a jedno ID. Pokud je ID uvedeno vícekrát, použije se poslední. + +Složené závorky obsahují CSS styly nebo HTML atributy. Styly se píší ve standardním CSS formátu property:value. Více stylů se odděluje středníky. Některé property jsou rozpoznány jako HTML atributy - například `{href:url}` se převede na atribut href, ne na CSS style. To umožňuje nastavit atributy, které není možné vyjádřit jinak. + +Zarovnání se zadává pomocí speciálních znaků. `<` znamená vlevo, `>` vpravo, `=` pro do bloku, `<>` pro na střed. Vertikální zarovnání používá `^` pro nahoru, `-` pro střed a `_` pro dolů. Tyto zkratky se převádějí buď na CSS třídy nebo inline styly podle konfigurace. + +Části modifikátoru mohou být v libovolném pořadí a některé mohou být vynechány. Platný je modifikátor obsahující jen třídy `.[highlight]`, jen title `.(Poznámka)` nebo jen styl `.{color:blue}`. Parser rozpozná jednotlivé části podle ohraničujících znaků. + + +Modifier třída +============== + +Třída `Modifier` slouží k parsování a uchovávání informací z modifikátoru. + +Instance `Modifier` se typicky vytváří syntax handler, který předá konstruktoru text modifikátoru extrahovaný z regex matche. Konstruktor zavolá metodu `setProperties()`, která parsuje text a naplní properties objektu. + +Veřejné properties obsahují jednotlivé části modifikátoru. Property `$id` obsahuje ID elementu jako řetězec nebo null. Property `$classes` je asociativní pole, kde klíče jsou názvy tříd a hodnoty jsou true. Property `$styles` je asociativní pole mapující CSS property na hodnoty. Property `$attrs` je asociativní pole s HTML atributy, které nejsou styly ani třídy. + +Dvě speciální properties `$hAlign` a `$vAlign` obsahují horizontální a vertikální zarovnání jako řetězce `left`, `right`, `center`, `justify` nebo `top`, `middle`, `bottom`. Tyto hodnoty se později převádějí na CSS třídy nebo styly podle konfigurace Texy. + +Property `$title` obsahuje text z kulatých závorek, který se použije jako title atribut nebo alt text u obrázků. Text je automaticky unescapován z HTML entit a zbaven escapovaných závorek. + + +Aplikace na elementy +==================== + +`Modifier` objekt se aplikuje na `HtmlElement` pomocí metody `Modifier::decorate()`. + +Metoda `decorate()` přijímá instanci Texy a `HtmlElement` jako parametry. Postupně aplikuje jednotlivé části modifikátoru na element s ohledem na konfiguraci Texy, která může některé části zakázat nebo omezit. + +Aplikace atributů kontroluje, které atributy jsou povolené pro daný tag podle `Texy::$allowedTags` konfigurace. Pokud jsou všechny atributy povolené, zkopírují se všechny atributy z `Modifier` do elementu. Pokud je povolen jen seznam konkrétních atributů, zkopírují se pouze ty, které jsou na seznamu. + +Title atribut se vždy aplikuje, pokud je nastaven, ale text prochází typografickým post-processingem pro nahrazení uvozovek a dalších úprav. + +Aplikace tříd a ID kontroluje konfiguraci `Texy::$allowedClasses`. Pokud jsou všechny třídy povolené, přidají se všechny třídy z `Modifier` do elementu a nastaví se ID. Pokud je povolen jen seznam konkrétních tříd, přidají se pouze ty, které jsou na seznamu. ID se přidá, jen pokud je v seznamu povolen řetězec začínající mřížkou. + +Aplikace stylů probíhá podobně s kontrolou `Texy::$allowedStyles`. Povolené CSS properties se přidají do style atributu elementu. Pokud element již měl nějaké styly, modifikátorové styly se přidají nebo přepíšou existující. + +Zarovnání se aplikuje buď jako CSS třída nebo inline style. Pokud je v Texy konfigurováno `Texy::$alignClasses` mapování pro daný typ zarovnání, přidá se odpovídající CSS třída. Pokud ne, přidá se inline style s text-align nebo vertical-align property. + +Výsledkem je, že element má všechny atributy, třídy, styly a další vlastnosti z modifikátoru, ale pouze ty, které jsou povoleny aktuální konfigurací Texy. To zajišťuje bezpečnost při zpracování nedůvěryhodného vstupu. + + +Propagace modifikátorů +====================== + +Modifikátory procházejí systémem v několika fázích, přičemž si zachovávají flexibilitu a umožňují úpravy na různých úrovních. + +Syntax handler extrahuje text modifikátoru z regex matche a vytvoří novou instanci `Modifier` a naplní se jeho properties. + +`Modifier` objekt se předává jako parametr do element handlerů. Handler dostává již parsovaný objekt, ne surový text. To umožňuje handleru snadno přistupovat k jednotlivým částem modifikátoru - třídám, stylům, zarovnání. Handler může modifikátor upravit před aplikací, například přidat další třídy nebo změnit styly. + +Element handler vytváří `HtmlElement` a předá jej metodě `Modifier::decorate()`. V tomto okamžiku se modifikátor aplikuje na element. Metoda `decorate()` kontroluje konfigurace Texy a zajišťuje, že se aplikují pouze povolené části. + +V některých případech modul kombinuje více modifikátorů. Například TableModule parsuje modifikátory na úrovni tabulky, řádků i buněk. Modifikátor buňky je vlastně klony modifikátoru sloupce, na kterém se pak aplikují dodatečné úpravy z modifikátoru konkrétní buňky. To umožňuje výchozí styly pro celý sloupec s možností přepsání v jednotlivých buňkách. diff --git a/texy/cs/configuration.texy b/texy/cs/configuration.texy new file mode 100644 index 0000000000..39f95f7469 --- /dev/null +++ b/texy/cs/configuration.texy @@ -0,0 +1,719 @@ +Konfigurace +*********** + +.[perex] +Kompletní průvodce konfigurací Texy. Naučíte se ovládat všechny moduly, nastavit bezpečnost a přizpůsobit Texy vašim potřebám. + +Texy se konfiguruje pomocí **public properties** hlavní třídy `Texy\Texy` a jejích **modulů**. Každý modul je zodpovědný za zpracování konkrétní části syntaxe (obrázky, odkazy, nadpisy...). + +Základní přístup: + +```php +$texy = new Texy\Texy; + +// Konfigurace hlavní třídy +$texy->allowedTags = Texy\Texy::NONE; + +// Konfigurace modulu +$texy->imageModule->root = '/images/'; +``` + + +Třída Texy\Texy .[#texy-class] +============================== + +Hlavní třída obsahuje globální nastavení a vlastnosti ovlivňující celé zpracování. + + +Povolené syntaxe ($allowed) .{toc: $allowed} +-------------------------------------------- + +Pole `$allowed` kontroluje, které části Texy syntaxe jsou aktivní: + +```php +// Výchozí: všechny syntaxe povoleny (kromě emotikonů) +$texy->allowed['image'] = true; +$texy->allowed['emoticon'] = false; + +// Vypnout obrázky +$texy->allowed['image'] = false; + +// Vypnout HTML značky ve vstupu +$texy->allowed['html/tag'] = false; +$texy->allowed['html/comment'] = false; + +// Vypnout různé typy odkazů +$texy->allowed['link/reference'] = false; +$texy->allowed['link/email'] = false; +$texy->allowed['link/url'] = false; +``` + +**Kompletní seznam syntaxí:** + +|--- +| Klíč | Výchozí | Popis +|--- +| `image` | `true` | Obrázky `[* img.jpg *]` +| `figure` | `true` | Obrázky s popiskou +| `link/reference` | `true` | Reference `[ref]` +| `link/email` | `true` | Email adresy +| `link/url` | `true` | Automatické URL +| `link/definition` | `true` | Definice referencí +| `heading/underlined` | `true` | Podtržené nadpisy +| `heading/surrounded` | `true` | Ohraničené nadpisy +| `horizline` | `true` | Horizontální čáry +| `blockquote` | `true` | Citace +| `list` | `true` | Seznamy +| `list/definition` | `true` | Definiční seznamy +| `table` | `true` | Tabulky +| `phrase/strong` | `true` | Tučné písmo `**text**` +| `phrase/em` | `true` | Kurzíva `//text//` +| `phrase/em-alt` | `true` | Kurzíva `*text*` +| `phrase/code` | `true` | Kód ```text``` +| `phrase/ins` | `false` | Vložený text `++text++` +| `phrase/del` | `false` | Smazaný text `--text--` +| `phrase/sup` | `false` | Horní index `^^text^^` +| `phrase/sub` | `false` | Dolní index `__text__` +| `html/tag` | `true` | HTML značky ve vstupu +| `html/comment` | `true` | HTML komentáře +| `emoticon` | `false` | Emotikony `:-)`, `:-(` +| `blocks` | `true` | Bloky `/-- \--` +| `typography` | `true` | Typografické úpravy +| `longwords` | `true` | Dělení dlouhých slov + + +Povolené HTML značky ($allowedTags) .{toc: $allowedTags} +-------------------------------------------------------- + +Kontroluje, které HTML značky mohou být ve výstupu (a na vstupu): + +```php +// Výchozí: všechny validní HTML5 značky povoleny +$texy->allowedTags = Texy\Texy::ALL; + +// Zakázat všechny HTML značky +$texy->allowedTags = Texy\Texy::NONE; + +// Povolit jen konkrétní značky +$texy->allowedTags = [ + 'strong' => [], // bez atributů + 'a' => ['href', 'title'], // s atributy + 'img' => Texy\Texy::ALL, // s jakýmikoliv atributy +]; +``` + +**Formáty:** +- `Texy::ALL` – všechny značky povoleny +- `Texy::NONE` – žádné značky povoleny +- Pole – povolené značky jako klíče, povolené atributy jako hodnoty + + +Povolené CSS třídy ($allowedClasses) .{toc: $allowedClasses} +------------------------------------------------------------ + +Kontroluje, které CSS třídy a ID mohou být použity: + +```php +// Výchozí: všechny třídy a ID povoleny +$texy->allowedClasses = Texy\Texy::ALL; + +// Zakázat třídy a ID +$texy->allowedClasses = Texy\Texy::NONE; + +// Povolit konkrétní třídy a ID +$texy->allowedClasses = [ + 'highlight', + 'important', + '#main', // ID začínají # + '#sidebar', +]; +``` + +Použití: +```texy +Text s třídou .[highlight] + +Text s ID .{toc: main} +``` + + +Povolené CSS styly ($allowedStyles) .{toc: $allowedStyles} +---------------------------------------------------------- + +Kontroluje, které inline CSS vlastnosti mohou být použity: + +```php +// Výchozí: všechny styly povoleny +$texy->allowedStyles = Texy\Texy::ALL; + +// Zakázat inline styly +$texy->allowedStyles = Texy\Texy::NONE; + +// Povolit konkrétní CSS vlastnosti +$texy->allowedStyles = [ + 'color', + 'background-color', + 'font-size', +]; +``` + +Použití: +```texy +Text s barvou .{color: red} +``` + + +CSS třídy pro zarovnání ($alignClasses) .{toc: $alignClasses} +------------------------------------------------------------- + +Místo inline stylů `style="text-align:left"` můžete použít CSS třídy: + +```php +// Výchozí: prázdné pole (použijí se inline styly) +$texy->alignClasses = [ + 'left' => null, + 'right' => null, + 'center' => null, + 'justify' => null, + 'top' => null, + 'middle' => null, + 'bottom' => null, +]; + +// Nastavit třídy +$texy->alignClasses['left'] = 'text-left'; +$texy->alignClasses['right'] = 'text-right'; +$texy->alignClasses['center'] = 'text-center'; +``` + +Použití: +```texy +Text zarovnaný doleva . + +Text zarovnaný doprava .> +``` + +S nastaveným `alignClasses` vygeneruje `

` místo `

`. + + +Další vlastnosti +---------------- + +```php +// Spojování řádků do odstavců (výchozí: true) +$texy->mergeLines = true; + +// Šířka tabulátoru (výchozí: 8) +$texy->tabWidth = 8; + +// Maskování emailů před roboty (výchozí: true) +$texy->obfuscateEmail = true; + +// Odstraňování měkkých spojovníků (výchozí: true) +$texy->removeSoftHyphens = true; + +// Element pro netextové odstavce (výchozí: 'div') +$texy->nontextParagraph = 'div'; +``` + + +Moduly +====== + +Každý modul zpracovává konkrétní část syntaxe. Moduly jsou přístupné jako public properties třídy `Texy\Texy`. + + +HeadingModule +------------- + +Zpracovává nadpisy (podtržené i ohraničené). + +```php +// Úroveň nejvyššího nadpisu (výchozí: 1) +$texy->headingModule->top = 1; //

+ +// Generovat automatická ID (výchozí: false) +$texy->headingModule->generateID = true; + +// Prefix pro generovaná ID (výchozí: 'toc-') +$texy->headingModule->idPrefix = 'section-'; + +// Více znaků = vyšší nadpis? (výchozí: true) +$texy->headingModule->moreMeansHigher = true; + +// Režim vyvažování (výchozí: DYNAMIC) +$texy->headingModule->balancing = Texy\Modules\HeadingModule::DYNAMIC; +``` + +Po zpracování: + +```php +// První nadpis (pro ) +echo $texy->headingModule->title; + +// Obsah (Table of Contents) +print_r($texy->headingModule->TOC); +``` + + +PhraseModule +------------ + +Zpracovává inline formátování (tučné, kurzíva, odkazy v textu...). + +```php +// HTML značky pro jednotlivé fráze (výchozí: viz níže) +$texy->phraseModule->tags = [ + 'phrase/strong' => 'strong', + 'phrase/em' => 'em', + 'phrase/code' => 'code', + // ... další +]; + +// Povolit odkazy ve frázích (výchozí: true) +$texy->phraseModule->linksAllowed = true; +``` + + +LinkModule +---------- + +Zpracovává odkazy, reference a URL. + +```php +// Kořenová cesta pro odkazy (výchozí: '') +$texy->linkModule->root = '/articles/'; + +// CSS třída pro odkazy na obrázky (výchozí: null) +$texy->linkModule->imageClass = 'image-link'; + +// Vždy přidávat rel="nofollow" (výchozí: false) +$texy->linkModule->forceNoFollow = false; + +// Zkracovat URL na čitelnější formu (výchozí: true) +$texy->linkModule->shorten = true; +``` + +**Reference:** + +```php +// Přidat referenci +$link = new Texy\Link('https://example.com'); +$link->modifier->title = 'Ukázková stránka'; +$link->label = 'Příklad'; +$texy->linkModule->addReference('example', $link); +``` + +Použití: +```texy +Odkaz na [example] +``` + + +ImageModule +----------- + +Zpracovává obrázky. + +```php +// Kořenová cesta pro obrázky (výchozí: 'images/') +$texy->imageModule->root = '/assets/images/'; + +// Kořenová cesta pro linkované obrázky (výchozí: 'images/') +$texy->imageModule->linkedRoot = '/assets/images/full/'; + +// Fyzická cesta na disku (pro zjištění rozměrů) +$texy->imageModule->fileRoot = __DIR__ . '/public/images/'; + +// CSS třída pro plovoucí obrázky (výchozí: null) +$texy->imageModule->leftClass = 'float-left'; +$texy->imageModule->rightClass = 'float-right'; + +// Výchozí alternativní text (výchozí: '') +$texy->imageModule->defaultAlt = 'Obrázek'; +``` + +**Reference:** + +```php +// Přidat referenci +$image = new Texy\Image; +$image->URL = 'photo.jpg'; +$image->modifier->title = 'Fotografie'; +$texy->imageModule->addReference('photo', $image); +``` + + +FigureModule +------------ + +Zpracovává obrázky s popiskou. + +```php +// HTML element (výchozí: 'div') +$texy->figureModule->tagName = 'figure'; + +// CSS třída (výchozí: 'figure') +$texy->figureModule->class = 'photo-figure'; + +// Třídy pro plovoucí obrázky (výchozí: null) +$texy->figureModule->leftClass = 'figure-left'; +$texy->figureModule->rightClass = 'figure-right'; + +// Offset pro výpočet šířky (výchozí: 10) +$texy->figureModule->widthDelta = 20; + +// Vyžadovat popisku (výchozí: true) +$texy->figureModule->requireCaption = true; +``` + + +ListModule +---------- + +Zpracovává odrážkové, číslované a definiční seznamy. + +```php +// Definice odrážek a stylu (výchozí: viz zdrojový kód) +$texy->listModule->bullets = [ + '*' => ['\*[\ \t]', 0, ''], + '-' => ['[\x{2013}-](?![>-])', 0, ''], + // ... další +]; +``` + + +TableModule +----------- + +Zpracovává tabulky. + +```php +// CSS třídy pro řádky (výchozí: null) +$texy->tableModule->oddClass = 'odd'; +$texy->tableModule->evenClass = 'even'; +``` + +*Poznámka: `oddClass` a `evenClass` jsou deprecated.* + + +HorizLineModule +--------------- + +Zpracovává horizontální čáry. + +```php +// CSS třídy podle typu (výchozí: null) +$texy->horizLineModule->classes = [ + '-' => 'hr-line', + '*' => 'hr-star', +]; +``` + + +TypographyModule +---------------- + +Zpracovává typografické úpravy. + +```php +// Locale (výchozí: 'cs') +$texy->typographyModule->locale = 'en'; +``` + +**Podporované locales:** +- `cs` – české uvozovky „text" a ‚text' +- `en` – anglické uvozovky "text" a 'text' +- `fr` – francouzské uvozovky «text» a ‹text› +- `de` – německé uvozovky „text" a ‚text' +- `pl` – polské uvozovky „text" a ‚text' + + +LongWordsModule +--------------- + +Rozděluje dlouhá slova pomocí `­`. + +```php +// Maximální délka slova (výchozí: 20) +$texy->longWordsModule->wordLimit = 25; +``` + + +EmoticonModule +-------------- + +Nahrazuje emotikony za obrázky nebo Unicode znaky. + +```php +// CSS třída (výchozí: null) +$texy->emoticonModule->class = 'emoji'; + +// Cesta k obrázkům (výchozí: null = použije imageModule->root) +$texy->emoticonModule->root = '/images/smilies/'; +$texy->emoticonModule->fileRoot = __DIR__ . '/public/smilies/'; + +// Definice emotikonů (výchozí: základní sada) +$texy->emoticonModule->icons = [ + ':-)' => '🙂', + ':-(' => '☹', + ';-)' => '😉', + // ... nebo cesty k obrázkům + ':cool:' => 'cool.gif', +]; +``` + + +HtmlModule +---------- + +Zpracovává HTML značky a komentáře ve vstupním textu. + +```php +// Zobrazit HTML komentáře na výstupu (výchozí: true) +$texy->htmlModule->passComment = true; +``` + + +HtmlOutputModule +---------------- + +Formátuje výstupní HTML. + +```php +// Formátovat výstup (odsazení) (výchozí: true) +$texy->htmlOutputModule->indent = true; + +// Základní odsazení (výchozí: 0) +$texy->htmlOutputModule->baseIndent = 0; + +// Maximální šířka řádku (výchozí: 80) +$texy->htmlOutputModule->lineWrap = 100; + +// Zachovat mezery v těchto elementech (výchozí: seznam) +$texy->htmlOutputModule->preserveSpaces = [ + 'textarea', 'pre', 'script', 'code', +]; +``` + + +ScriptModule +------------ + +Zpracovává volání `{{makro}}`. + +```php +// Oddělovač argumentů (výchozí: ',') +$texy->scriptModule->separator = ';'; +``` + + +Třída Texy\Configurator .{toc: Texy\Configurator} +================================================= + +Předpřipravené konfigurační sety pro časté use-case. + + +safeMode() – Bezpečný režim .{toc: safeMode()} +---------------------------------------------- + +Konfigurace pro zpracování **nedůvěryhodného obsahu** od uživatelů. + +```php +Texy\Configurator::safeMode($texy); +``` + +**Co dělá:** +- Zakáže třídy a ID (`$allowedClasses = NONE`) +- Zakáže inline styly (`$allowedStyles = NONE`) +- Povolí jen bezpečné HTML značky: + +```php +[ + 'a' => ['href', 'title'], + 'abbr' => ['title'], + 'b' => [], + 'br' => [], + 'cite' => [], + 'code' => [], + 'em' => [], + 'i' => [], + 'strong' => [], + 'sub' => [], + 'sup' => [], + 'q' => [], + 'small' => [], +] +``` + +- Filtruje URL schémata (jen `http:`, `https:`, `ftp:`, `mailto:`) +- Zakáže obrázky +- Zakáže definice referencí +- Zakáže HTML komentáře +- Přidá `rel="nofollow"` ke všem odkazům + + +disableLinks() – Vypnout odkazy .{toc: disableLinks()} +------------------------------------------------------ + +Zakáže všechny typy odkazů. + +```php +Texy\Configurator::disableLinks($texy); +``` + +**Co dělá:** +- Zakáže všechny typy odkazů (`link/reference`, `link/email`, `link/url`, `link/definition`) +- Zakáže odkazy ve frázích (`phraseModule->linksAllowed = false`) +- Odebere `<a>` z povolených značek + + +disableImages() – Vypnout obrázky .{toc: disableImages()} +--------------------------------------------------------- + +Zakáže všechny typy obrázků. + +```php +Texy\Configurator::disableImages($texy); +``` + +**Co dělá:** +- Zakáže obrázky (`image`, `figure`, `image/definition`) +- Odebere `<img>`, `<object>`, `<embed>`, `<applet>` z povolených značek + + +Bezpečnost +========== + +Texy je navrženo s důrazem na bezpečnost. Automaticky chrání před běžnými útoky. + + +Ochrana proti XSS +----------------- + +Cross-Site Scripting (XSS) je útok, kdy útočník vloží škodlivý JavaScript do stránky. + +**Příklad útoků, které Texy zablokuje:** + +```texy +Pokus o útok: <script>alert('XSS')</script> + +Pokus o útok: <img src=x onerror="alert('XSS')"> + +Pokus o útok: "klikni":javascript:alert('XSS') + +Pokus o útok: [* image.jpg onload="alert('XSS')" *] +``` + +Texy automaticky: +- **Validuje HTML** – odstraní nepovolené značky a atributy +- **Filtruje URL** – povolí jen bezpečná schémata (`http:`, `https:`, `mailto:`, `ftp:`) +- **Escapuje obsah** – správně escapuje text v atributech +- **Sanitizuje atributy** – odstraní event handlery (`onclick`, `onerror`, ...) + +```php +$texy = new Texy\Texy; +Texy\Configurator::safeMode($texy); + +$input = '<script>alert("XSS")</script>'; +$output = $texy->process($input); + +// Výstup: prázdný (script tag odstraněn) +``` + + +Validace URL +------------ + +Texy kontroluje URL ve všech odkazech a obrázcích: + +```php +$texy = new Texy\Texy; + +// Nastavit povolená schémata (výchozí v safeMode) +$texy->urlSchemeFilters[Texy\Texy::FILTER_ANCHOR] = + '#https?:|ftp:|mailto:#Ai'; +$texy->urlSchemeFilters[Texy\Texy::FILTER_IMAGE] = + '#https?:#Ai'; +``` + +**Příklady blokovaných URL:** + +```texy +"útok":javascript:alert('XSS') // blokováno +"útok":data:text/html,<script> // blokováno +[* javascript:alert() *] // blokováno +``` + + +Filtrování HTML značek +---------------------- + +Kontrola přes `$allowedTags`: + +```php +$texy = new Texy\Texy; + +// Povolit jen bezpečné značky +$texy->allowedTags = [ + 'p' => [], + 'strong' => [], + 'em' => [], + 'a' => ['href', 'title'], // jen tyto atributy +]; + +$input = '<p>Text <script>alert()</script></p>'; +$output = $texy->process($input); + +// Výstup: <p>Text alert()</p> +// (script tag odstraněn) +``` + + +Praktický příklad +----------------- + +```php +function processComment(string $userInput): string +{ + $texy = new Texy\Texy; + + // Bezpečný režim + Texy\Configurator::safeMode($texy); + + // Dodatečná omezení + $texy->allowed['link/url'] = false; // zakázat auto-linky + $texy->allowed['html/tag'] = false; // zakázat HTML + + // Zpracovat + return $texy->process($userInput); +} + +// Použití +$comment = $_POST['comment']; +$html = processComment($comment); +echo $html; // bezpečný výstup +``` + + +Best practices +-------------- + +1. **Vždy použijte safeMode()** pro uživatelský obsah +2. **Validujte vstup** před předáním Texy (délka, formát) +3. **Limitujte HTML značky** podle potřeby +4. **Kontrolujte výstup** – i když Texy je bezpečné, double-check nikdy neuškodí +5. **Logujte podezřelé pokusy** – může vám pomoci identifikovat útočníky + +```php +$texy = new Texy\Texy; +Texy\Configurator::safeMode($texy); + +// Logování +$texy->addHandler('htmlTag', function($invocation, $el, $isStart) { + if ($el->getName() === 'script') { + error_log('XSS attempt detected!'); + } + return $invocation->proceed(); +}); +``` diff --git a/texy/cs/custom-handlers.texy b/texy/cs/custom-handlers.texy new file mode 100644 index 0000000000..3cc43d4b78 --- /dev/null +++ b/texy/cs/custom-handlers.texy @@ -0,0 +1,850 @@ +Úprava chování prvků +******************** + +.[perex] +Tato kapitola popisuje, jak můžete změnit chování **existujících prvků** v Texy - například upravit, jak se zpracovávají obrázky, odkazy nebo formátování. Pokud chcete přidat **zcela novou syntaxi**, kterou Texy standardně nezná, přečtěte si kapitolu [Přidání vlastní syntaxe |custom-syntax]. + +Představte si, že chcete, aby standardní syntaxe pro obrázky `[* URL *]` rozpoznávala speciální adresu `[* youtube:dQw4w9WgXcQ *]` a místo běžného obrázku vytvořila embedded přehrávač. + +Nebo chcete obarvovat výpisy zdrojového kódu pomocí syntax highlighteru. A tak dále. Přesně k tomu slouží **element handlery** - funkce, které Texy volá při zpracování konkrétních prvků. Například zaregistrujete handler pro element `image`, který zkontroluje URL, a pokud začíná `youtube:`, vrátí iframe místo standardního obrázku. Neměníte syntaxi, jen upravujete, co se s nalezenou konstrukcí stane. + + +Elementy a jejich handlery +========================== + +V terminologii Texy je **element** název pro typ prvku, který může být v dokumentu zpracován. Například `image` je element pro obrázky, `linkURL` pro odkazy, viz [#výchozí elementy]. Každý element má svůj **výchozí handler**, který je implementován v příslušném modulu a stará se o standardní zpracování. + +Když napíšete v textu `[* image.jpg *]`, parser najde tuto syntaxi, vytvoří objekt `Texy\Image` s daty o obrázku a zavolá všechny handlery zaregistrované pro element `image`. Pokud žádný vlastní handler není, zavolá se pouze výchozí handler z `ImageModule`, který vytvoří HTML tag `<img>`. + +Handler zaregistrujete voláním metody `addHandler()`: + +```php +$texy->addHandler('image', function( + Texy\HandlerInvocation $invocation, + Texy\Image $image, + ?Texy\Link $link, +) { + // zde bude vaše logika +}); +``` + +První parametr je název elementu, druhý je callback funkce. Callback dostává jako první parametr vždy objekt `Texy\HandlerInvocation`, následují parametry jsou specifické pro daný element. + +.[note] +Podrobné vysvětlení všech typů handlerů najdete v kapitole [Architektura a principy |architecture]. + + +Jak funguje zpracování +====================== + +Když Texy potřebuje zpracovat element, vytvoří objekt `HandlerInvocation` obsahující všechny zaregistrované handlery pro tento typ prvku. **Váš handler se zavolá jako první** a může: + +- **Delegovat** na další handler voláním `$invocation->proceed()` +- **Upravit vstup** voláním `proceed()` s modifikovanými parametry +- **Upravit výstup** zpracováním výsledku z `proceed()` +- **Přerušit řetěz** vrácením vlastního výsledku bez volání `proceed()` + +Metoda `proceed()` posune zpracování na další handler v řetězu. Pokud už žádný vlastní handler není, zavolá se výchozí implementace z modulu. To znamená, že váš handler má absolutní kontrolu - může rozhodnout, zda se vůbec zavolá výchozí logika. + +Tento mechanismus se nazývá **chain of responsibility** (řetěz zodpovědnosti): + +```php +$texy->addHandler('image', function( + Texy\HandlerInvocation $invocation, + Texy\Image $image, + ?Texy\Link $link, +) { + // 1. Upravíme vstupní data před zpracováním + $image->modifier->title = 'Modified title'; + + // 2. Zavoláme další handler nebo výchozí zpracování + $element = $invocation->proceed($image, $link); + + // 3. Upravíme výsledný HTML element + $element->attrs['loading'] = 'lazy'; + + return $element; +}); +``` + +Pořadí vykonávání je od **posledně registrovaného k prvnímu**. Pokud modul zaregistruje svůj výchozí handler při konstrukci a vy pak zaregistrujete vlastní handler, váš handler se zavolá první. To vám umožňuje přepsat nebo obalit výchozí chování. + + +Výchozí elementy +================ + +Texy poskytuje několik předpřipravených elementů, pro které můžete registrovat vlastní handlery. Zde je jejich kompletní seznam s parametry, které dostává handler. + + +image +----- + +Zpracovává obrázky. + +```php +function( + Texy\HandlerInvocation $invocation, + Texy\Image $image, + ?Texy\Link $link, +): Texy\HtmlElement|string|null +``` + +Parametr `$image` obsahuje URL, rozměry a modifikátory. Parametr `$link` je zadán, pokud je obrázek odkazem (syntaxe `[* img *]:url`). + + +linkReference +------------- + +Zpracovává referenční odkazy typu `[ref]`. + +```php +function( + Texy\HandlerInvocation $invocation, + Texy\Link $link, + string $content, +): Texy\HtmlElement|string|null +``` + +Parametr `$link` obsahuje URL a modifikátory načtené z definice reference. Parametr `$content` je HTML obsah odkazu (již zpracovaný parsováním inline syntaxí). + + +linkEmail +--------- + +Zpracovává automaticky rozpoznané emailové adresy v textu. + +```php +function( + Texy\HandlerInvocation $invocation, + Texy\Link $link, +): Texy\HtmlElement|string|null +``` + +Parametr `$link` obsahuje emailovou adresu v property `URL`. + + +linkURL +------- + +Zpracovává automaticky rozpoznané URL v textu. + +```php +function( + Texy\HandlerInvocation $invocation, + Texy\Link $link, +): Texy\HtmlElement|string|null +``` + +Parametr `$link` obsahuje nalezenou URL. + + +phrase +------ + +Zpracovává inline formátování. + +```php +function( + Texy\HandlerInvocation $invocation, + string $phrase, + string $content, + Texy\Modifier $modifier, + ?Texy\Link $link, +): Texy\HtmlElement|string|null +``` + +Parametr `$phrase` je název syntaxe jako `phrase/strong` nebo `phrase/em`. Parametr `$content` je text uvnitř formátování. Parametr `$modifier` obsahuje CSS třídy, styly a další modifikátory. Parametr `$link` je zadán, pokud má formátování připojený odkaz. + + +newReference +------------ + +Volá se, když parser najde referenci, která není definovaná. + +```php +function( + Texy\HandlerInvocation $invocation, + string $name, +): Texy\HtmlElement|string|null +``` + +Parametr `$name` je název reference. Handler může vytvořit odkaz dynamicky nebo vrátit `null` pro odmítnutí. + + +htmlComment +----------- + +Zpracovává HTML komentáře. + +```php +function( + Texy\HandlerInvocation $invocation, + string $content, +): string +``` + +Parametr `$content` je text mezi `<!--` a `-->`. + + +htmlTag +------- + +Zpracovává HTML tagy v textu. + +```php +function( + Texy\HandlerInvocation $invocation, + Texy\HtmlElement $el, + bool $isStart, + ?bool $forceEmpty, +): Texy\HtmlElement|string|null +``` + +Parametr `$el` je element s názvem a atributy. Parametr `$isStart` určuje, zda jde o otevírací tag. Parametr `$forceEmpty` vynutí prázdný element. + + +script +------ + +Zpracovává skripty `{{command: args}}`. + +```php +function( + Texy\HandlerInvocation $invocation, + string $command, + array $args, + ?string $raw, +): Texy\HtmlElement|string|null +``` + +Parametr `$command` je název příkazu. Parametr `$args` je pole argumentů. Parametr `$raw` je původní neparsovaný řetězec argumentů. + + +figure +------ + +Zpracovává obrázky s popiskou. + +```php +function( + Texy\HandlerInvocation $invocation, + Texy\Image $image, + ?Texy\Link $link, + string $content, + Texy\Modifier $modifier, +): Texy\HtmlElement|null +``` + +Parametr `$content` je text popisky pod obrázkem. + + +heading +------- + +Zpracovává nadpisy. + +```php +function( + Texy\HandlerInvocation $invocation, + int $level, + string $content, + Texy\Modifier $modifier, + bool $isSurrounded, +): Texy\HtmlElement +``` + +Parametr `$level` je úroveň nadpisu (0-6). Parametr `$content` je text nadpisu. Parametr `$isSurrounded` určuje, zda jde o ohraničený nadpis (`###`) nebo podtržený. + + +horizline +--------- + +Zpracovává horizontální čáry. + +```php +function( + Texy\HandlerInvocation $invocation, + string $type, + Texy\Modifier $modifier, +): Texy\HtmlElement +``` + +Parametr `$type` je řetězec znaků použitých pro čáru (`---` nebo `***`). + + +block +----- + +Zpracovává speciální bloky `/--type` až `\--`. + +```php +function( + Texy\HandlerInvocation $invocation, + string $blocktype, + string $content, + ?string $param, + Texy\Modifier $modifier, +): Texy\HtmlElement|string +``` + +Parametr `$blocktype` je typ bloku s prefixem `block/`, např. `block/code` nebo `block/html`. Parametr `$content` je obsah bloku. Parametr `$param` je volitelný parametr za typem (např. jazyk u kódu). + + +emoticon +-------- + +Zpracovává emotikony (smajlíky). + +```php +function( + Texy\HandlerInvocation $invocation, + string $emoticon, + string $raw, +): Texy\HtmlElement|string +``` + +Parametr `$emoticon` je rozpoznaný emotikon (např. `:-)` nebo `:-(` ). Parametr `$raw` je původní text včetně případných opakujících se znaků (např. `:-)))))` ). + +.[note] +Emotikony jsou ve výchozím nastavení **vypnuté**. Zapnete je pomocí `$texy->allowed['emoticon'] = true;` + + +Výchozí eventy +============== + +Texy poskytuje několik předpřipravených eventů, pro které můžete registrovat handlery. Říká se jim **notification handlery**. Na rozdíl od element handlerů tyto handlery **nic nevrací**. Používají se pro vedlejší efekty jako logování, sběr statistik nebo úpravy již vytvořeného DOM stromu. + + +beforeParse +----------- + +Volá se před začátkem parsování textu. Umožňuje provést předzpracování nebo načíst definice. + +```php +function( + Texy\Texy $texy, + string &$text, + bool $isSingleLine, +): void +``` + +Parametr `$text` je předán referencí, takže ho můžete upravit. Parametr `$isSingleLine` určuje, zda se parsuje jeden řádek nebo celý dokument. + + +afterParse +---------- + +Volá se po dokončení parsování, před konverzí DOM stromu na HTML. Umožňuje upravit vytvořený DOM. + +```php +function( + Texy\Texy $texy, + Texy\HtmlElement $DOM, + bool $isSingleLine, +): void +``` + +Parametr `$DOM` je kořenový element dokumentu, který můžete procházet a upravovat. + + +afterList +--------- + +Volá se po vytvoření seznamu (číslovaného nebo nečíslovaného). + +```php +function( + Texy\BlockParser $parser, + Texy\HtmlElement $element, + Texy\Modifier $modifier, +): void +``` + +Parametr `$element` je vytvořený element `<ul>` nebo `<ol>`. Parametr `$modifier` obsahuje modifikátory aplikované na celý seznam. + + +afterDefinitionList +------------------- + +Volá se po vytvoření definičního seznamu. + +```php +function( + Texy\BlockParser $parser, + Texy\HtmlElement $element, + Texy\Modifier $modifier, +): void +``` + +Parametr `$element` je vytvořený element `<dl>`. + + +afterTable +---------- + +Volá se po vytvoření tabulky. + +```php +function( + Texy\BlockParser $parser, + Texy\HtmlElement $element, + Texy\Modifier $modifier, +): void +``` + +Parametr `$element` je vytvořený element `<table>`. + + +afterBlockquote +--------------- + +Volá se po vytvoření citace. + +```php +function( + Texy\BlockParser $parser, + Texy\HtmlElement $element, + Texy\Modifier $modifier, +): void +``` + +Parametr `$element` je vytvořený element `<blockquote>`. + + +Základní použití +================ + +Nejjednodušší element handler jen deleguje na výchozí zpracování: + +```php +$texy->addHandler('image', function( + Texy\HandlerInvocation $invocation, + Texy\Image $image, + ?Texy\Link $link, +) { + return $invocation->proceed(); +}); +``` + +Tento handler nic nemění, ale ukazuje základní kostru. Všechny parametry předá dál a vrátí výsledek. + + +Úprava vstupních dat +-------------------- + +Handler může upravit data před jejich zpracováním: + +```php +$texy->addHandler('image', function( + Texy\HandlerInvocation $invocation, + Texy\Image $image, + ?Texy\Link $link, +) { + // přidáme default rozměry, pokud nejsou zadané + $image->width ??= 800; + $image->height ??= 600; + return $invocation->proceed(); +}); +``` + +Změny provedené na objektech `$image` nebo `$link` se projeví v dalším zpracování, včetně výchozího handleru. + + +Úprava výstupního elementu +-------------------------- + +Handler může upravit HTML element vrácený z `proceed()`: + +```php +$texy->addHandler('image', function( + Texy\HandlerInvocation $invocation, + Texy\Image $image, + ?Texy\Link $link, +) { + $element = $invocation->proceed(); + + if ($element) { + // přidáme lazy loading + $element->attrs['loading'] = 'lazy'; + + // přidáme CSS třídu + $element->attrs['class'][] = 'responsive'; + } + + return $element; +}); +``` + + +Podmíněné zpracování +-------------------- + +Handler může zpracovat pouze určité případy a ostatní delegovat: + +```php +$texy->addHandler('image', function( + Texy\HandlerInvocation $invocation, + Texy\Image $image, + ?Texy\Link $link, +) { + // speciální zpracování pro YouTube videa + if (str_starts_with($image->URL, 'youtube:')) { + $id = substr($image->URL, 8); + $iframe = sprintf( + '<iframe src="https://youtube.com/embed/%s"></iframe>', + htmlspecialchars($id) + ); + return $invocation->getTexy() + ->protect($iframe, Texy\Texy::CONTENT_BLOCK); + } + + // ostatní obrázky zpracujeme standardně + return $invocation->proceed(); +}); +``` + + +Přerušení zpracování +-------------------- + +Handler může odmítnout zpracování vrácením `null`: + +```php +$texy->addHandler('image', function( + Texy\HandlerInvocation $invocation, + Texy\Image $image, + ?Texy\Link $link, +) { + // zakážeme externí obrázky + if (str_contains($image->URL, '://')) { + return null; + } + + return $invocation->proceed(); +}); +``` + + +Praktické příklady +================== + +Následující příklady ukazují reálné use-case pro element handlery. + + +YouTube embed +------------- + +Převod speciální syntaxe na embedded video: + +```php +$texy->addHandler('image', function( + Texy\HandlerInvocation $invocation, + Texy\Image $image, + ?Texy\Link $link, +) { + if (str_starts_with($image->URL, 'youtube:')) { + $id = substr($image->URL, 8); + $width = $image->width ?: 560; + $height = $image->height ?: 315; + + $iframe = sprintf( + '<iframe width="%d" height="%d" ' + . 'src="https://youtube.com/embed/%s" ' + . 'frameborder="0" allowfullscreen></iframe>', + $width, $height, htmlspecialchars($id) + ); + + $texy = $invocation->getTexy(); + return $texy->protect($iframe, $texy::CONTENT_BLOCK); + } + + return $invocation->proceed(); +}); +``` + +Použití v textu: + +```texy +[* youtube:dQw4w9WgXcQ 640x360 *] +``` + + +Galerie obrázků +--------------- + +Obalení obrázků do speciálního divu pro lightbox: + +```php +$texy->addHandler('image', function( + Texy\HandlerInvocation $invocation, + Texy\Image $image, + ?Texy\Link $link, +) { + $element = $invocation->proceed(); + + // pokud má obrázek třídu 'gallery' + if (isset($image->modifier->classes['gallery'])) { + // obalíme do divu s lightbox atributy + $wrapper = new Texy\HtmlElement('div'); + $wrapper->attrs['class'][] = 'lightbox-item'; + $wrapper->attrs['data-src'] = $image->URL; + $wrapper->add($element); + + return $wrapper; + } + + return $element; +}); +``` + +Použití: + +```texy +[* image.jpg .[gallery] *] +``` + + +Validace odkazů +--------------- + +Kontrola, zda odkazy nalezené v textu vedou na povolené domény: + +```php +$allowedDomains = ['example.com', 'trusted.org']; + +$texy->addHandler('linkURL', function( + Texy\HandlerInvocation $invocation, + Texy\Link $link, +) use ($allowedDomains) { + $host = parse_url($link->URL, PHP_URL_HOST); + + // pokud doména není v whitelistu, nepovolíme odkaz + if ($host && !in_array($host, $allowedDomains, true)) { + return null; + } + + return $invocation->proceed(); +}); +``` + + +Automatické rel="nofollow" +-------------------------- + +Přidání `nofollow` všem externím odkazům nalezeným v textu: + +```php +$texy->addHandler('linkURL', function( + Texy\HandlerInvocation $invocation, + Texy\Link $link, +) { + $element = $invocation->proceed(); + + // pokud odkaz obsahuje // (tedy je externí) + if (str_contains($link->URL, '://')) { + $element->attrs['rel'] = 'nofollow'; + } + + return $element; +}); +``` + + +Syntax highlighting +------------------- + +Integrace knihovny pro zvýraznění syntaxe: + +```php +$texy->addHandler('block', function( + Texy\HandlerInvocation $invocation, + string $blocktype, + string $content, + ?string $param, + Texy\Modifier $modifier, +) { + // zpracujeme pouze bloky typu 'code' + if ($blocktype !== 'block/code') { + return $invocation->proceed(); + } + + // aplikujeme syntax highlighting + $highlighter = new MyHighlighter(); + $highlighted = $highlighter->highlight($content, $param); + + $el = new Texy\HtmlElement('pre'); + $modifier->decorate($invocation->getTexy(), $el); + $el->attrs['class'][] = 'language-' . $param; + + $code = new Texy\HtmlElement('code'); + $code->add($highlighted); + $el->add($code); + + return $el; +}); +``` + + +Lazy loading +------------ + +Projdeme všechny obrázky a přidáme lazy loading: + +```php +$texy->addHandler('afterParse', function( + Texy\Texy $texy, + Texy\HtmlElement $DOM, + bool $isSingleLine, +) { + foreach ($DOM->getIterator() as $child) { + if ($child instanceof Texy\HtmlElement + && $child->getName() === 'img' + ) { + $child->attrs['loading'] = 'lazy'; + } + } +}); +``` + + +Logování použitých prvků +------------------------ + +Sběr statistik o použitých prvcích v dokumentu: + +```php +$stats = []; + +$texy->addHandler('beforeParse', function( + Texy\Texy $texy, + string &$text, + bool $isSingleLine, +) use (&$stats) { + $stats = ['images' => 0, 'links' => 0, 'headings' => 0]; +}); + +$texy->addHandler('image', function( + Texy\HandlerInvocation $invocation, + Texy\Image $image, + ?Texy\Link $link, +) use (&$stats) { + $stats['images']++; + return $invocation->proceed(); +}); + +$texy->addHandler('linkURL', function( + Texy\HandlerInvocation $invocation, + Texy\Link $link, +) use (&$stats) { + $stats['links']++; + return $invocation->proceed(); +}); + +$texy->addHandler('heading', function( + Texy\HandlerInvocation $invocation, + int $level, + string $content, + Texy\Modifier $modifier, + bool $isSurrounded, +) use (&$stats) { + $stats['headings']++; + return $invocation->proceed(); +}); +``` + + +Pomocné třídy +============= + +Při práci s handlery budete pracovat s několika důležitými třídami. Zde je jejich přehled s nejdůležitějšími vlastnostmi. + + +Texy\Image +---------- + +Reprezentuje obrázek s jeho parametry: + +```php +$image->URL; // string - cesta k obrázku +$image->linkedURL; // ?string - URL odkazu (pokud je obrázek odkazem) +$image->width; // ?int - šířka v pixelech +$image->height; // ?int - výška v pixelech +$image->asMax; // bool - zda jsou rozměry maximální +$image->modifier; // Modifier - CSS třídy, styly, atributy +$image->name; // ?string - název reference +``` + + +Texy\Link +--------- + +Reprezentuje odkaz s jeho parametry: + +```php +$link->URL; // string - cílová URL +$link->raw; // string - původní URL (před normalizací) +$link->modifier; // Modifier - CSS třídy, styly, atributy +$link->type; // string - typ odkazu (COMMON, BRACKET, IMAGE) +$link->label; // ?string - text odkazu (u referencí) +$link->name; // ?string - název reference +``` + +Konstanty pro typ odkazu: + +```php +Texy\Link::COMMON; // běžný odkaz +Texy\Link::BRACKET; // referenční odkaz [ref] +Texy\Link::IMAGE; // odkaz z obrázku [* img *] +``` + + +Texy\HtmlElement +---------------- + +Reprezentuje HTML element s jeho atributy a obsahem: + +```php +$el = new Texy\HtmlElement('div'); + +// práce s názvem elementu +$el->getName(); // vrací 'div' +$el->setName('section'); // změní na 'section' + +// práce s atributy +$el->attrs['id'] = 'main'; +$el->attrs['class'][] = 'container'; +$el->attrs['style']['color'] = 'red'; + +// práce s obsahem +$el->setText('text'); // nastaví textový obsah +$el->getText(); // vrací textový obsah +$el->add($child); // přidá potomka +$el->insert(0, $child); // vloží potomka na pozici + +// parsování obsahu +$el->parseLine($texy, $text); // parsuje inline text +$el->parseBlock($texy, $text); // parsuje blokový text + +// konverze na HTML +$el->toString($texy); // internal reprezentace +$el->toHtml($texy); // finální HTML +``` + + +Texy\Modifier +------------- + +Reprezentuje modifikátory CSS tříd, stylů a atributů: + +```php +$mod->id; // ?string - HTML id +$mod->classes; // array - pole CSS tříd +$mod->styles; // array - pole CSS stylů +$mod->attrs; // array - HTML atributy +$mod->hAlign; // ?string - horizontální zarovnání (left, right, center, justify) +$mod->vAlign; // ?string - vertikální zarovnání (top, middle, bottom) +$mod->title; // ?string - title atribut nebo alt pro obrázky + +// aplikace modifikátoru na element +$mod->decorate($texy, $element); +``` diff --git a/texy/cs/custom-syntax.texy b/texy/cs/custom-syntax.texy new file mode 100644 index 0000000000..f8f7634b5c --- /dev/null +++ b/texy/cs/custom-syntax.texy @@ -0,0 +1,519 @@ +Přidání vlastní syntaxe +*********************** + +.[perex] +Tato kapitola popisuje, jak přidat do Texy **zcela nové markup konstrukce**, které standardně neexistují. Pokud chcete pouze změnit chování existujících prvků (například upravit zpracování obrázků nebo odkazů), přečtěte si kapitolu [Úprava chování prvků |custom-handlers]. + +Představte si, že chcete v dokumentaci automaticky vytvářet odkazy na uživatelské profily zápisem `@@username`. Nebo potřebujete speciální bloky pro upozornění typu `:::warning`. Texy tyto konstrukce nezná a nemůžete je vytvořit úpravou existujících prvků. + +Vlastní syntaxe vám umožní definovat nové markup konstrukce. Zadáte, jak má konstrukce vypadat (pomocí regulárního výrazu), a napíšete funkci, která ji zpracuje. Texy pak vaši syntaxi rozpozná stejně jako své standardní konstrukce. + + +Registrace syntaxe +================== + +Texy poskytuje dvě metody pro registraci vlastní syntaxe podle toho, zda jde o inline nebo blokový prvek. + + +Line syntaxe +------------ + +Line syntaxe slouží pro inline konstrukce uvnitř řádků textu. Registrujete ji metodou `registerLinePattern()`: + +```php +$texy->registerLinePattern( + callable $handler, + string $pattern, + string $name, + ?string $againTest = null, +); +``` + +**Parametr `$handler`** je callback funkce, která se zavolá při nálezu syntaxe. Může to být název funkce, anonymní funkce nebo pole `[$object, 'method']`. + +**Parametr `$pattern`** je regulární výraz (PCRE), který definuje, jak vaše syntaxe vypadá v textu. Pattern by **neměl být kotvený** na začátek řádku (`^`), protože se hledá kdekoliv v textu. Použijte capturing groups pro zachycení dat, která potřebujete zpracovat. + +**Parametr `$name`** je unikátní název syntaxe. Používá se v poli `$texy->allowed` pro zapnutí/vypnutí a předává se do handleru pro identifikaci. Doporučujeme používat prefixový styl jako `custom/username` nebo `myapp/profile`. + +**Parametr `$againTest`** je volitelný regex pro optimalizaci. Pokud je zadán, Texy nejprve zkontroluje, zda text vůbec obsahuje něco, co by mohlo matchnout váš pattern. Teprve pokud `$againTest` uspěje, spustí se komplexnější pattern. To výrazně zrychlí zpracování, pokud máte složitý pattern a používá se jen zřídka. + +Příklad registrace: + +```php +$texy->registerLinePattern( + 'usernameHandler', + '#@@([a-z0-9_]+)#i', + 'custom/username', +); +``` + + +Block syntaxe +------------- + +Block syntaxe slouží pro víceřádkové blokové konstrukce. Registrujete ji metodou `registerBlockPattern()`: + +```php +$texy->registerBlockPattern( + callable $handler, + string $pattern, + string $name, +); +``` + +Parametry `$handler` a `$name` mají stejný význam jako u line syntaxí. + +**Parametr `$pattern`** je regulární výraz, který **musí být kotvený** na začátek řádku (`^`) a často i na konec (`$`). BlockParser automaticky přidá modifikátory `Am` (anchored, multiline), takže je do patternu nepřidávejte. Pattern by měl matchnout celý blok nebo alespoň jeho začátek. + +Příklad registrace: + +```php +$texy->registerBlockPattern( + 'alertHandler', + '#^:::(warning|info|danger)\n(.+)$#s', + 'custom/alert', +); +``` + + +Syntax handler +============== + +Syntax handler je funkce volaná parserem, když najde výskyt vaší syntaxe v textu. Jeho úkolem je zpracovat nalezená data a vrátit HTML element nebo řetězec. + +Podrobné vysvětlení role syntax handleru v architektuře Texy najdete v kapitole [Architektura a principy |architecture#syntax-handler]. + + +Pro line syntaxe +---------------- + +Signatura syntax handleru pro line syntaxe: + +```php +function( + Texy\LineParser $parser, + array $matches, + string $name, +): Texy\HtmlElement|string|null +``` + +**Parametr `$parser`** poskytuje přístup k parseru a Texy objektu. Nejčastěji použijete `$parser->getTexy()` pro získání Texy instance. + +**Parametr `$matches`** obsahuje výsledky regex matche. `$matches[0]` je celý matchnutý řetězec, `$matches[1]`, `$matches[2]` atd. jsou capturing groups z vašeho patternu. + +**Parametr `$name`** je název syntaxe, který jste zadali při registraci. Užitečné, pokud jeden handler zpracovává více syntaxí. + +**Návratová hodnota** může být `Texy\HtmlElement` pro strukturovaný HTML výstup, `string` pro přímý HTML kód (který musíte protectovat), nebo `null` pro odmítnutí zpracování. + +Handler může nastavit `$parser->again = true`, pokud chce, aby se obsah vytvořeného elementu znovu parsoval pro nalezení vnořených syntaxí. + + +Pro block syntaxe +----------------- + +Signatura syntax handleru pro block syntaxe: + +```php +function( + Texy\BlockParser $parser, + array $matches, + string $name, +): Texy\HtmlElement|string|null +``` + +Parametry mají stejný význam jako u line syntaxí, jen dostáváte `Texy\BlockParser` místo `LineParser`. + +BlockParser poskytuje metody pro práci s víceřádkovými strukturami: + +- **`$parser->next($pattern, &$matches)`** - matchne další řádek proti patternu a vrátí true/false +- **`$parser->moveBackward($lines)`** - vrátí se o zadaný počet řádků zpět +- **`$parser->isIndented()`** - vrací true, pokud je aktuální blok odsazený + + +LineParser API +============== + +Při práci s line syntaxemi máte k dispozici několik užitečných vlastností a metod. + +**Property `$again`** řídí, zda se má právě zpracovaná syntaxe hledat znovu na stejné pozici po zpracování. Výchozí hodnota je `false`. Nastavte na `true`, pokud vytváříte element s obsahem, který může obsahovat další syntaxe: + +```php +function( + Texy\LineParser $parser, + array $matches, + string $name, +): Texy\HtmlElement +{ + $el = new Texy\HtmlElement('span'); + $el->setText($matches[1]); + + // obsah může obsahovat další formátování + $parser->again = true; + + return $el; +} +``` + +**Metoda `getTexy()`** vrací instanci Texy objektu, což potřebujete pro práci s `protect()` nebo přístup ke konfiguraci. + + +BlockParser API +=============== + +Při práci s block syntaxemi máte k dispozici metody pro práce s víceřádkovými strukturami. + +**Metoda `next($pattern, &$matches)`** zkusí matchnout další řádek v textu proti zadanému patternu. Pokud uspěje, naplní `$matches` výsledkem a posune interní pozici za tento řádek. Vrací `true` při úspěchu, `false` při neúspěchu: + +```php +while ($parser->next('#^\-\s+(.+)$#', $matches)) { + // zpracuj další položku seznamu + $item = $matches[1]; +} +``` + +**Metoda `moveBackward($lines = 1)`** vrátí interní pozici o zadaný počet řádků zpět. Užitečné, když váš pattern matchnul víc než začátek bloku a chcete se vrátit na začátek: + +```php +// pattern matchnul 3 řádky, ale chceme číst od prvního +$parser->moveBackward(2); +``` + +**Metoda `isIndented()`** vrací `true`, pokud je aktuální blok odsazený (začíná mezerou nebo tabulátorem). To naznačuje, že jde o vnořený obsah. + + +Praktické příklady +================== + +Následující příklady ukazují reálné use-case pro vlastní syntaxe. + + +Uživatelské profily +------------------- + +Automatické vytváření odkazů na profily zápisem `@@username`: + +```php +$texy->registerLinePattern( + function( + Texy\LineParser $parser, + array $matches, + string $name, + ): Texy\HtmlElement + { + $username = $matches[1]; + + $el = new Texy\HtmlElement('a'); + $el->attrs['href'] = '/user/' . urlencode($username); + $el->attrs['class'][] = 'user-profile'; + $el->setText('@' . $username); + + return $el; + }, + '#@@([a-z0-9_]+)#i', + 'custom/username' +); +``` + +Použití v textu: + +```texy +Podívejte se na profil @@johndoe nebo @@jane_smith. +``` + + +Alert boxy +---------- + +Speciální bloky pro upozornění s různými typy: + +```php +$texy->registerBlockPattern( + function( + Texy\BlockParser $parser, + array $matches, + string $name, + ): Texy\HtmlElement + { + $type = $matches[1]; // warning, info, danger + $content = $matches[2]; + + $el = new Texy\HtmlElement('div'); + $el->attrs['class'][] = 'alert'; + $el->attrs['class'][] = 'alert-' . $type; + + $texy = $parser->getTexy(); + $el->parseBlock($texy, trim($content)); + + return $el; + }, + '#^:::(warning|info|danger)\n(.+?)(?=\n:::|$)#s', + 'custom/alert' +); +``` + +Použití v textu: + +```texy +:::warning +Toto je důležité upozornění! +::: + +:::info +Pro informaci: aktualizace proběhne zítra. +::: +``` + + +Hashtagy +-------- + +Automatické vytváření odkazů z hashtagů: + +```php +$texy->registerLinePattern( + function( + Texy\LineParser $parser, + array $matches, + string $name, + ): Texy\HtmlElement + { + $tag = $matches[1]; + + $el = new Texy\HtmlElement('a'); + $el->attrs['href'] = '/tag/' . urlencode($tag); + $el->attrs['class'][] = 'hashtag'; + $el->setText('#' . $tag); + + return $el; + }, + '#\#([a-z0-9_]+)#i', + 'custom/hashtag', + '#\##' // optimalizace - hledej jen pokud je # v textu +); +``` + +Použití: + +```texy +Článek o #php a #webdesign. +``` + + +Zkratky +------- + +Automatické rozbalení zkratek s vysvětlením: + +```php +$abbreviations = [ + 'HTML' => 'HyperText Markup Language', + 'CSS' => 'Cascading Style Sheets', + 'PHP' => 'PHP: Hypertext Preprocessor', +]; + +$texy->registerLinePattern( + function( + Texy\LineParser $parser, + array $matches, + string $name + ) use ($abbreviations): ?Texy\HtmlElement + { + $abbr = $matches[1]; + + if (!isset($abbreviations[$abbr])) { + return null; // neznámá zkratka + } + + $el = new Texy\HtmlElement('abbr'); + $el->attrs['title'] = $abbreviations[$abbr]; + $el->setText($abbr); + + return $el; + }, + '#\b([A-Z]{2,})\b#', + 'custom/abbreviation' +); +``` + + +Inline ikony +------------ + +Vkládání ikon pomocí speciální syntaxe: + +```php +$texy->registerLinePattern( + function( + Texy\LineParser $parser, + array $matches, + string $name, + ): Texy\HtmlElement + { + $icon = $matches[1]; + + $el = new Texy\HtmlElement('i'); + $el->attrs['class'][] = 'icon'; + $el->attrs['class'][] = 'icon-' . $icon; + $el->attrs['aria-hidden'] = 'true'; + + return $el; + }, + '#:icon-([a-z-]+):#', + 'custom/icon' +); +``` + +Použití: + +```texy +Klikněte na tlačítko :icon-download: pro stažení. +``` + + +Poznámkový blok +--------------- + +Blok pro poznámky pod čarou: + +```php +$texy->registerBlockPattern( + function( + Texy\BlockParser $parser, + array $matches, + string $name + ): Texy\HtmlElement + { + $parser->moveBackward(); + + $content = ''; + while ($parser->next('#^NOTE:\s*(.+)$#', $matches)) { + $content .= $matches[1] . "\n"; + } + + $el = new Texy\HtmlElement('aside'); + $el->attrs['class'][] = 'note'; + + $texy = $parser->getTexy(); + $el->parseBlock($texy, trim($content)); + + return $el; + }, + '#^NOTE:\s*(.+)$#m', + 'custom/note' +); +``` + +Použití: + +```texy +NOTE: Toto je důležitá poznámka. +NOTE: Může být víceřádková. +``` + + +Vlastní citace s autorem +------------------------ + +Rozšířená syntaxe pro citace s uvedením autora: + +```php +$texy->registerBlockPattern( + function( + Texy\BlockParser $parser, + array $matches, + string $name, + ): Texy\HtmlElement + { + $author = $matches[1]; + $quote = $matches[2]; + + $blockquote = new Texy\HtmlElement('blockquote'); + + $texy = $parser->getTexy(); + $blockquote->parseBlock($texy, trim($quote)); + + $cite = new Texy\HtmlElement('cite'); + $cite->setText($author); + $blockquote->add($cite); + + return $blockquote; + }, + '#^QUOTE\[([^\]]+)\]:\n(.+?)(?=\n\n|$)#s', + 'custom/quote' +); +``` + +Použití: + +```texy +QUOTE[Albert Einstein]: +Fantazie je důležitější než vědění, +protože vědění je omezené. +``` + + +Galerie obrázků +--------------- + +Speciální blok pro vytvoření galerie z více obrázků: + +```php +$texy->registerBlockPattern( + function( + Texy\BlockParser $parser, + array $matches, + string $name, + ): Texy\HtmlElement + { + $parser->moveBackward(); + + $gallery = new Texy\HtmlElement('div'); + $gallery->attrs['class'][] = 'gallery'; + + while ($parser->next('#^\[G\]\s*(.+)$#', $matches)) { + $img = new Texy\HtmlElement('img'); + $img->attrs['src'] = trim($matches[1]); + $img->attrs['loading'] = 'lazy'; + $gallery->add($img); + } + + return $gallery; + }, + '#^\[G\]\s*(.+)$#m', + 'custom/gallery' +); +``` + +Použití: + +```texy +[G] image1.jpg +[G] image2.jpg +[G] image3.jpg +``` + + +Kolize syntaxí +============== + +Když registrujete vlastní syntaxi, musíte dávat pozor, aby nekolidovala s existujícími syntaxemi Texy nebo s jinými vlastními syntaxemi. + +**Pořadí registrace záleží.** Line syntaxe se hledají v pořadí, jak byly registrovány. Pokud více syntaxí může matchnout na stejné pozici, vyhrává ta, která byla registrována dříve. Proto registrujte specifičtější syntaxe před obecnějšími. + +**Buďte specifičtí v patterns.** Čím konkrétnější je váš pattern, tím menší je riziko kolize. Pattern `#\#\w+#` matchne i `#hashtag`, což by mohlo kolidovat s nadpisy. Lepší je `#(?<=\s)\#[a-z0-9_]+#i`, který vyžaduje mezeru před hashtagem. + +**Testujte kombinace.** Vyzkoušejte, jak vaše syntaxe funguje v kombinaci s existujícími konstrukcemi. Co se stane, když je váš markup uvnitř odkazu? Co když je uvnitř code bloku? + +**Používejte prefixované názvy.** Místo `username` použijte `custom/username` nebo `myapp/username`. To zabrání konfliktům, pokud by Texy v budoucnu přidalo syntaxi stejného názvu. + + +Best practices +============== + +**Vracejte `null` při neúspěchu.** Pokud handler zjistí, že nemůže nebo nechce zpracovat daný match (například neznámá zkratka), vraťte `null`. Parser pak zkusí další syntaxe. + +**Používejte `protect()` pro HTML.** Pokud vracíte raw HTML string místo `HtmlElement`, musíte ho protectovat pomocí `$texy->protect($html, Texy::CONTENT_...)`. Jinak bude escapován. + +**Nastavte `$parser->again` správně.** Pro line syntaxe, které vytváří element s textovým obsahem, který může obsahovat další syntaxe (formátování, odkazy), nastavte `$parser->again = true`. + +**Respektujte `$texy->allowed`.** Pokud vytváříte modul s více syntaxemi, kontrolujte `$texy->allowed[$name]` před registrací patternu nebo v handleru před zpracováním. diff --git a/texy/cs/develop.texy b/texy/cs/develop.texy new file mode 100644 index 0000000000..cc388cd830 --- /dev/null +++ b/texy/cs/develop.texy @@ -0,0 +1,35 @@ +Pro programátory +**************** + +.[perex] +Vítejte v programátorské dokumentaci Texy! Tato sekce vás provede od základního použití až po pokročilé techniky rozšíření a vlastní syntaxe. + + +[Rychlý start | quickstart] +--------------------------- + +Instalace, první použití a základní konfigurace. Za 5 minut budete mít Texy funkční. + + +[Konfigurace | configuration] +----------------------------- + +Kompletní přehled všech modulů, jejich vlastností a konfiguračních možností. Nastavení bezpečnosti, povolených značek, stylů a tříd. + + +[Úprava chování prvků | custom-handlers] +---------------------------------------- + +Naučte se měnit chování existující syntaxe. YouTube embedování, syntax highlighting, custom validace. + + +[Přidání vlastní syntaxe | custom-syntax] +----------------------------------------- + +Vytvoření zcela nových syntaktických prvků. + + +[Architektura a principy | architecture] +---------------------------------------- + +Pochopení toho, jak Texy interně funguje. Parsing flow, moduly, pattern matching, protect/unprotect mechanismus. diff --git a/texy/cs/napsali-o-texy.texy b/texy/cs/napsali-o-texy.texy new file mode 100644 index 0000000000..c5906f0ba8 --- /dev/null +++ b/texy/cs/napsali-o-texy.texy @@ -0,0 +1,160 @@ +Napsali o Texy +************** + +{{nofollow:yes}} + +> Při volbě formátovače textu pro poslední dva weby jsme zkusili oproti dříve používaným WYSIWYG editorům implementovat systém Texy Davida Grudla, a nestačili jsme se divit. Neuvěřitelně komplexní formátovací možnosti, úžasná podpora české typografie a předem připravené instalační balíčky dělají Texy vynikajícím publikačním doplňkem. +> +> [Jan Brašna Alphanumeric | http://www.alphanumeric.cz] (3. 5. 2005) + + +> Dobrý den, s Texy jsem neuvěřitelně spokojen. Mnohokráte děkuji. +> +> Využíváme Texy jak na firemních stránkách www.logio.cz v sekci Novinky tak na našem novém projektu www.skladuj.cz. +> +> Dokonce si někteří kolegové navykli posílat příspěvky již předformátované v emailu. Což je neuvěřitelné. +> +> [Tomáš Formánek | http://www.skladuj.cz] (10. 4. 2006) + + +> Zdravím. Texy jsem začal používat na nokturno.net - je to luxusní věcička, hlavně dá minimálně práce zakomponovat jej do systému. +> +> [Jiří Reiter | http://www.nokturno.net] (5. 3. 2006) + + +> Použil jsem jej pro formátování aktuálních zpráviček na našem firemním webu. Celé zahrnutí trvalo cca hodinu, včetně pochopení o co jde a zavedení příznaku pro přepínání pro starší zprávy v HTML. Zadávání je teď výrazně intuitivnější a je menší riziko "rozhození" formátování stránek při ev. chybě v textu zprávy. +> +> Brilantní kus kódu, jak návrh, tak realizace. +> +> [Ing. Zdeněk Trojánek | http://www.daisy.cz] (3. 3. 2006) + + +> Nejprve jsem chtěl do svého implementovat nějaký wysiwyg editor, ale našel jsem Texy. +> +> Něco podobného jsem zatím nevidel, uplně nadchnul. Dokud nevyzkoušíte neuvěříte. +> +> [Petr Čada | http://error414.php5.cz/] (24. 11. 2005) + + + +> Texy je velmi šikovná a praktická věc, která dokáže i překvapit... spokojenost je určitě na místě. +> +> [Petr Vlček | http://saabinfo.net] (4. 10. 2005) + + +> Na Texy ma prekvapila jeho komplexnosť a sila. Umožňuje formátovať text akokoľvek len chcete, pritom dbá aj na správne postavenie predložiek a rozdelenie dlhých slov atď. Rozhodne Texy vyskúšajte. +> +> [Michal Poppe | http://www.mipo.ssag.sk/zapisnik/webowiny/2005-02-08-texy-konecne-vonku.html] (8. 2. 2005) + + +> Texy jsem implementoval do nekomerční obrázkové encyklopedie. Texy se mi stará o doprovodné texty k tématickým sekcím a já mám z toho, jak to dělá (dělá to hezky sexy ;-) ), **velikou radost**. Texy mi ušetří čas, a tak mám Texy rád a autorovi za něj děkuji tímto a ikonkou. +> +> Hlavně oceňuji logickou a jenoduchou syntaxi, jednoduchou implementaci do jiných php systémů, komplexnost. :) +> +> [Robert Nový | http://www.jablicko.cz] (18. 4. 2005) + + +> Texy používám už delší dobu jako svou hlavní pomůcku pro převod textů do HTML, což dělám v práci vlastně denně. +> +> [Jirka Chomát | http://www.chomat.net/articles/trublog] (5. 3. 2005) + + +> Ano je to tak. Skutečně používáme tento skvělý "převaděč textu do formátovaného HTML kódu". +> +> [WordPress CZ | http://wordpress.cz] (24. 2. 2005) + + +> **Elegance v phpRS .. to je Texy** Osobně mi vůbec nevadí psát příspěvky včetně TAGů, mám potom vše pod kontrolou a vím "wo co de !". Proč si ale neušetřit práci použitím formátovače Texy. Přeci jen jsem občas líný tvor a Texy je podle mě opravdu super. Celá operace "zasunutí" Texy do phpRS je velice jednoduchá +> +> [Pykaso | http://pykaso.net/?article=elegance-v-phprs-to-je-texy] (11. 3. 2005) + + +> Texy, skvělý nástroj od Davida Grudla (dgx), který usnadní práci nejen pisálkům, ale i těm, kteří komentují, jsem původně zamýšlel používat pouze k formátování komentářů - ode dneška jej používám i k formátování mnou napsaných článků. +> +> A co mě k tomu vedlo? Pohodlost! Člověk by nevěřil, jak je všechno najednou jednoduché +> +> [Luboš Bretschneider | http://www.bretik.com/?page=article&article=Texy-je-sexy-Texy-je-cool] (2. 3. 2005) + + +> Texy jsem si zaimplementoval do webu spíš jen tak. Chtěl jsem ho vyzkoušet a napadlo mě, že to můžu zkusit rovnou v reálu. Nečekal jsem nic nepřevratného, a to byla chyba. Texy mě úplně vzalo. +> +> Dnes už vůbec neuvažuji nad WYSIWYG editorem. Texy je pro mě jasná volba pro jednoduché, ale i složité formátování textů do XHTML. Což je věc, kterou Texy zvládá na jedničku! +> +> [Lukáš Knop, Knopdesign | http://www.knopdesign.net] (17. 3. 2005) + + +> **Texy je opravdu sexy** Texy využívám i já. Texy totiž není program jen pro neznalé HTML a počítačové analfabety, ale i pro ostřílené webdevelopery. Dnes jsem ho využil k převedení dlouhého textu do kódu pro jedny stránky, na kterých teď usilovně pracuji. Usnadní mi nudnou práci a tím pádem jsem o něco efektivnější... +> +> [Ondřej Kůrka | http://bernardyn.bloguje.cz/109088_item.php/] (1. 2. 2005) + + +> Články se publikují v podstatě sami, protože využívám Texy, jehož stvořitelem je David Grudl. +> +> [Lazy Byte | http://lazybyte.wz.cz/blog/za%c4%8dinam-blogovat] (6. 3. 2005) + + +> Kód je napsán hezky objektově a přehledně, navíc řekl bych i hodně univerzálně, autor s řadou věcí počítá a tak je radost s Texy pracovat. Podpora UTF-8 hned v základu a hlavně dgx vážně nekecal, když psal, že zapracování do kódu bude snadné. +> +> [Vojtěch Schlesinger | http://www.php-weblog.com] (1. 2. 2005) + + +> Budu se ale muset hodně ovládat, abych nepsal s dokonalou Texy syntaxí ... tedy ne že bych ji já psal dokonale, ale že ona je dokonalá. S klidem přiznám, že jsem z Texy už několik dní nepokrytě nadšený. Takový vybroušený kousek php kódu jsem ještě neviděl. +> +> [Juneau | http://reality-show.net/?text=486-a-tak-si-mezi-programovanim-blognu] (26. 2. 2005) + + +> Texy hodnotím výborně, velice mi usnadňuje psaní článků. A plugin pro BLOG:CMS je taky super věc! :-) DĚKUJU ZA TEXY! :-) +> +> [Miroslav Navrátil | http://kanevinternetu.blacksuns.net/] (14. 3. 2005) + + +> ... umožní jednoduché a intuitivní formátování textu bez znalosti HTML, čistě za použití plain textu. ... Implementace systému do existující PHP aplikace už snad ani nemůže být jednodušší, stačí includovat jeden soubor a vytvořit jeden objekt, Texy se postará o zbytek +> +> [Adam Šindelář, Root.cz | http://www.root.cz/clanky/nova-softwarova-sklizen-16-3-2005/] (16. 3. 2005) + + +> Jsem se zas jednou nudil, serfoval po netu a narazil na Texy, mno a to mě tak nadchlo až jsem z toho začal předělávat celej webík. Texy vřele doporučuji všem, kteří jsou aspoň z poloviny tak líní jako já. Je vhodný jak pro laiky tak pro zkušené programátory. Je prostě sexy! +> +> [Rozi.net | http://www.rozi.net/text-32.html] (11. 3. 2005) + + +> Izsak's Weblog používa na formátovanie článkov a komentárov nový, jednoduchý a komplexný systém Texy. +> +> [Jozef Izso | http://www.izsak.net/weblog/47/prechod-na-textpattern] (23. 2. 2005) + + +> Zdravím! Texy využívám v mém blogu, sám bych texy asi nedokázal zasadit do nějakého rs, ale RS2 ho obsahuje a tak ho využívám, jsem naprosto spokejen, texy mi vyhovuje, práce s ním je hned příjemnější. Přeji hodně úspěchů. +> +> [Martin Světlík alias QuickShare | http://blog.msvetlik.com] (20. 4. 2006) + +> Cau, ted sem se dostal k Texy! Zatim pouzivam WYSIWYG editor napsany v JS. Dobry, jen nekdy pomaly a ten kod taky nic moc. Navic JS pouzivam nerad. Cetl sem si jak je to udelany a musim rict ze uvazuju nad tim ze bych to cely nahradil :o) +> +> Kanadsky bod pro tebe...kdyz sem se dival na formatovani tabulek... no musel jsi s tim mit strasnou praci. +> +> Keep on ;) +> +> [Marek | liq@quick.cz] (17. 11. 2005) + + +> Konečně mám (po hokeji) zase jednou důvod být hrdý, že jsem Čech, stejně jako autor Texy ;) Moc pěkný kousek software! Smekám... +> +> [Pavel Beníšek | http://www.3dgrafika.cz] (17. 3. 2005) + + +Dále Texy používá +----------------- + +- síť obchodů [Internet Mall | http://www.mall.cz/] +- [H1.cz | http://www.h1.cz/] +- [Vitalita | http://www.vitalita.cz] +- [Václavák | http://www.vaclavak.net] +- [Rarouš weblog | http://rarous.net/] (běží na ASP.NET) +- [La Trine | https://www.latrine.cz] +- **...a stovky dalších webů** + + +Texy najdete v sytémech: +------------------------ + +- [Český TextPattern | http://www.vaclavak.net/weblog/23/textpattern-pro-ceske-prostredi] +- Český WordPress diff --git a/texy/cs/quickstart.texy b/texy/cs/quickstart.texy new file mode 100644 index 0000000000..8c16245ab4 --- /dev/null +++ b/texy/cs/quickstart.texy @@ -0,0 +1,205 @@ +Rychlý start +************ + +.[perex] +Naučte se pracovat s Texy za pár minut. Tato stránka vás provede instalací, prvním použitím a základní konfigurací. + + +Instalace +========= + +Texy využívá moderních vlastností PHP a vyžaduje minimálně verzi 8.1. + +Nejjednodušší způsob instalace je přes Composer: + +```bash +composer require texy/texy +``` + +Composer automaticky stáhne Texy a všechny závislosti. + + +První použití +============= + + +Základní zpracování textu +------------------------- + +Vytvoření instance Texy a zpracování textu je extrémně jednoduché: + +```php +require __DIR__ . '/vendor/autoload.php'; + +$texy = new Texy\Texy; + +$text = 'Toto je **tučný text** a toto //kurzíva//.'; +$html = $texy->process($text); + +echo $html; +``` + +Výstup: +```latte +<p>Toto je <strong>tučný text</strong> a toto <em>kurzíva</em>.</p> +``` + +Metoda `process()` zpracuje celý text včetně blokových elementů (odstavce, nadpisy, seznamy, tabulky...). + + +Jednořádkový text +----------------- + +Pokud zpracováváte pouze jednořádkový text bez blokových elementů (například nadpisy v databázi, krátké popisky): + +```php +$texy = new Texy\Texy; + +$text = 'Odkaz na "homepage":https://example.com'; +$html = $texy->processLine($text); + +echo $html; +``` + +Výstup: +```latte +Odkaz na <a href="https://example.com">homepage</a> +``` + +Metoda `processLine()` nezabaluje výstup do odstavce `<p>` a zpracuje pouze inline elementy. + + +Základní konfigurace +==================== + +Texy funguje "out of the box", ale často budete chtít upravit základní nastavení. + + +Nastavení cest k obrázkům +------------------------- + +Pokud používáte relativní cesty k obrázkům, nastavte kořenový adresář: + +```php +$texy = new Texy\Texy; + +// Cesta na webu (přidá se před relativní URL) +$texy->imageModule->root = '/images/'; + +// Fyzická cesta na disku (pro zjištění rozměrů) +$texy->imageModule->fileRoot = __DIR__ . '/public/images/'; +``` + +Teď když napíšete `[* photo.jpg *]`, Texy vygeneruje `<img src="/images/photo.jpg">` a automaticky zjistí rozměry obrázku. + + +Nastavení cest k odkazům +------------------------ + +Podobně můžete nastavit kořenový adresář pro odkazy: + +```php +$texy->linkModule->root = '/articles/'; +``` + + +Povolení a zakázání syntaxí +--------------------------- + +Každá část Texy syntaxe lze vypnout nebo zapnout pomocí pole `$allowed`: + +```php +$texy = new Texy\Texy; + +// Vypnout obrázky +$texy->allowed['image'] = false; + +// Vypnout HTML značky ve vstupu +$texy->allowed['html/tag'] = false; + +// Povolit emotikony (ve výchozím stavu vypnuté) +$texy->allowed['emoticon'] = true; +``` + +Kompletní seznam syntaxí najdete v [konfiguraci | configuration#allowed]. + + +Bezpečný režim pro uživatelský obsah +------------------------------------ + +Pokud zpracováváte obsah od uživatelů (komentáře, příspěvky na fóru), použijte bezpečný režim: + +```php +$texy = new Texy\Texy; +Texy\Configurator::safeMode($texy); + +$userInput = $_POST['comment']; +$html = $texy->process($userInput); +``` + +SafeMode: +- Povolí jen **bezpečné HTML značky** (`<strong>`, `<em>`, `<a>`, ...) +- Zakáže **třídy a ID** +- Zakáže **inline styly** +- Zakáže **obrázky** +- Přidá `rel="nofollow"` ke všem odkazům +- Filtruje **URL schémata** (jen `http:`, `https:`, `ftp:`, `mailto:`) + +Více o bezpečnosti v kapitole [Konfigurace – Bezpečnost |configuration#Bezpečnost]. + + +Kompletní příklad +================= + +```php +require __DIR__ . '/vendor/autoload.php'; + +$texy = new Texy\Texy; + +// Konfigurace +$texy->imageModule->root = '/images/'; +$texy->linkModule->root = '/'; +$texy->allowed['html/tag'] = false; + +// Text k zpracování +$text = ' + + +Nadpis článku +============= + +Toto je **úvodní odstavec** s odkazem na "homepage":https://example.com. + +- První položka +- Druhá položka +- Třetí položka + +[* photo.jpg .(Fotografie) *] +'; + +// Zpracování +$html = $texy->process($text); + +// Výstup +echo $html; + +// Dodatečné informace +echo "Titulek stránky: " . $texy->headingModule->title; +print_r($texy->summary['links']); +print_r($texy->summary['images']); +``` + +Po zpracování máte k dispozici: +- `$texy->headingModule->title` – první nadpis (vhodné pro `<title>`) +- `$texy->summary['links']` – pole všech použitých odkazů +- `$texy->summary['images']` – pole všech použitých obrázků + + +Další kroky +=========== + +Teď už víte, jak Texy používat. Pokračujte: + +- **[Konfigurace | configuration]** – podrobné nastavení všech modulů +- **[Syntaxe | syntax]** – naučte se Texy markup +- **[Architektura | architecture]** – pochopte, jak Texy funguje uvnitř diff --git a/texy/cs/syntax.texy b/texy/cs/syntax.texy new file mode 100644 index 0000000000..a75396973c --- /dev/null +++ b/texy/cs/syntax.texy @@ -0,0 +1,891 @@ +Syntaxe +******* + +.[perex] +Texy vznikl proto, aby nezkušeným uživatelům umožnil snadno editovat obsah webových stránek. Proto je i syntaxe intuitivní a přehledná. + + +Cheat Sheet +=========== + +| [#Formátování textu] | Syntax +|----------------------------------------------- +| [Tučný text |#Formátování textu] | .[text-code] ''**tučný text**'' +| [Kurzíva |#Formátování textu] | ''*kurzíva*'' nebo ''//kurzíva//'' +| [Inline code |#Formátování textu] | ''`kód`'' +| [#Odkazy] | ''"text":URL'' nebo ''[text](URL)'' +| [#Obrázky] | ''[* image.jpg *]'' +| [#Vypnutí formátování] | ''specialní znaky'' +|----------------------------------------------- +| Elementy +|----------------------------------------------- +| [#Podtržené nadpisy] | H1 <br> === +| [#Ohraničené nadpisy] | ''### H1'' <br> ## H2 +| [#Odrážkové seznamy] | ''- první'' <br> ''- druhá'' +| [#Číslované seznamy] | ''1) první'' <br> ''2) druhá'' +| [#Seznamy definic] | term: <br>   ''- první'' +| [#Citace] | ''> blockquote'' +| [#Horizontální čáry] | ''---'' +| [#Tabulky] | ''\| buňka \| buňka \|'' +| [Bloky kódu|#Předformátovaný text] | ''/--'' <br> ... <br> ''\--'' +|----------------------------------------------- +| Modifikátory .[#toc-modifikatory] +|-------------------------------------------------------- +| titulek | ''.(titulek)'' +| CSS třída | ''.[btn btn-primary]'' +| ID | ''.[#id]'' +| CSS styl nebo HTML atribut | ''.{color: blue}'' nebo ''.{target: _blank}'' +| horizontální zarovnání | ''.< .> .<> .='' +| vertikální zarovnání | ''.^ .- ._'' + + +Odstavce textu +============== + +Za odstavec považuje Texy jeden nebo více řádků textu, které následují těsně za sebou. Jakmile mezi nimi necháte **jeden prázdný řádek**, Texy automaticky pochopí, že má začít nový odstavec. + +To znamená, že Texy spojí řádky, které patří k sobě. Nemusíte se tak bát, že se vám věta zalomí uprostřed, když si zmenšíte okno editoru. + +```texy +Toto je první odstavec. Může mít klidně více řádků +a Texy je spojí do jednoho souvislého bloku textu. + +Až tady, po prázdném řádku, začíná úplně nový, druhý odstavec. +``` + +Spojování řádků lze nicméně vypnout v konfiguraci a pak se každý řádek považuje za samostatný odstavec: + +/--php +$texy->mergeLines = false; +\-- + + +Zalomení řádků +-------------- + +Co když ale potřebujete text jen odřádkovat, aniž byste vytvářeli celý nový odstavec? To se typicky hodí u básní, textů písní nebo při psaní adresy. **Začněte nový řádek jednou mezerou**. + +```texy +Karel Novák, + U Tiché pošty 5 + 150 00 Praha 5 +``` + + +Stylování odstavců +------------------ + +Někdy potřebujete celý odstavec nějak odlišit – například z něj udělat úvodní perex článku, vycentrovat ho nebo mu přiřadit specifický styl pro rámeček. K tomu slouží [#modifikátory], které můžete umístit buď na samostatný řádek **před** odstavec, nebo na konec jeho posledního řádku. + +```texy +.[perex] +Toto je úvodní odstavec článku, který díky modifikátoru +dostane CSS třídu "perex" a může tak vypadat jinak než zbytek textu. + +Tento odstavec má zase přiřazené unikátní ID. .[#sekce-uvod] + +A tento odstavec bude vycentrován. .<> +``` + + +Formátování textu +================= + +| syntax | výstup | ID syntaxe +|----------------------------------------------------------------------------- +| .[text-code] ''**tučný text**'' | **tučný text** | `phrase/strong` +| ''*kurzíva* nebo //kurzíva//'' | *kurzíva* | `phrase/em-alt`, `phrase/em` +| ''***tučná kurzíva***'' | ***tučná kurzíva*** | `phrase/strong+em` +| ''`inline kód`'' | `inline kód` | `phrase/code` +| ''x^2 … O_2'' | x^2 … O_2 | `phrase/sup-alt`, `phrase/sub-alt` +| ''x^^2^^ … O__2__'' | x^2 … O_2 | `phrase/sup`🔸, `phrase/sup`🔸 +| ''++vložený text++'' | <ins>vložený text</ins> | `phrase/ins`🔸 +| ''--smazaný text--'' | <del>smazaný text</del> | `phrase/del`🔸 +| ''>>citovaný text<<'' | >>citovaný text<< | `phrase/quote` +| ''"modrý text .{color: blue}"'' | "modrý text .{color: blue}" | `phrase/span` +| ''~modrý text .{color: blue}~'' | ~modrý text .{color: blue}~ | `phrase/span-alt` +| ''"et al."((a další))'' | "et al."((a další)) | `phrase/acronym` +| ''NBA((National Basketball Association))'' | NBA((National Basketball Association)) | `phrase/acronym-alt` + +Syntaxe označené 🔸 nejsou ve výchozím stavu povolené a musíte je zapnout. Příklad: + +/--php +$texy->allowed['phrase/ins'] = true; +\-- + +Pro jednoduché číselné indexy můžete použít zkrácenou syntaxi `x^2` a `O_2`, ale pro složitější případy je robustnější varianta s dvojitými znaky, nebo můžete použít HTML značky `<sup>` a `<sub>`. + +Uvnitř syntaktických znaků **nesmí být mezery**: + +```texy +Špatně: ** toto nebude tučné ** +Správně: **toto bude tučné** +``` + + +Stylování textu +--------------- + +Tohle je jedna z nejsilnějších vlastností Texy. Ke každému formátovanému textu můžete "přilepit" [#modifikátory] a přidat mu tak CSS třídu, ID nebo přímý styl. Modifikátor se vždy vkládá **těsně před uzavírací značku**: + +```texy +Tento text je **silný a zelený .{color:green}** jako Hulk. + +Upozornění: --Tato funkce je zastaralá .[deprecated]-- +``` + +Pokud chcete aplikovat modifikátor na text, ale nechcete ho zároveň dělat tučným nebo kurzívou, použijte jako obalovací značku uvozovky `"` nebo vlnovky `~`. Texy z toho vytvoří univerzální HTML značku `<span>` s vašimi styly: + +```texy +Běžný text, ale "tento kousek je červený .{color: red}", a zbytek už ne. +``` + + +Formátování a odkazy v jednom +----------------------------- + +Z formátovaného textu můžete udělat odkaz - jednoduše přidejte dvojtečku a URL adresu: + +```texy +Navštivte naši **novou galerii**:https://example.com/gallery +``` + +Toto funguje pro tučný text, kurzívu, inline kód. + + +Psaní speciálních znaků +----------------------- + +Co když chcete napsat doslova `**text**` včetně hvězdiček, aniž by se z něj stal tučný text? Máte tři možnosti: + +- zpětné lomítko je nejrychlejší způsob, jak "zneplatnit" jeden speciální znak `\**text\**` +- dvojité apostrofy [vypnou Texy|#Vypnutí formátování] pro celou frázi `''**text**''` +- můžete použít standardní HTML entity `**text**` + + +Odkazy +====== + +Odkazy jsou duší internetu. V Texy je jejich tvorba navržena tak, aby byla co nejpřirozenější a nejpřehlednější přímo v textu. + +Základní syntaxe pro odkaz je jednoduchá a skvěle čitelná. Odkazovaný text uzavřete do `"` (nebo jiných znaků pro [#formátování textu]) a hned připojíte dvojtečku a cílovou URL adresu: + +```texy +Navštivte oficiální stránky projektu "Nette Framework":https://nette.org. + +Pokud máte dotaz, "napište nám":info@example.com. +``` + +Výhodou je, že Texy je inteligentní a samo pozná, kde URL končí. Nemusíte se tedy bát, že by do odkazu omylem zahrnulo tečku nebo čárku na konci věty. Pokud ale URL obsahuje nestandardní znaky, můžete je uzavřít do hranatých závorek a tím přesně řeknete, kde adresa začíná a končí: + +```texy +"Přečtěte si náš článek":[https://example.com/novinky?id=1&kategorie=články] +``` + +ID syntaxe `phrase/span`, `phrase/span-alt` | [PhraseModule |configuration#phrasemodule] a [LinkModule |configuration#linkmodule] + + +Alternativní syntaxe odkazů +--------------------------- + +Jste zvyklí na formát, který používá Markdown nebo Wikipedia? Texy rozumí i jim. Můžete si vybrat styl, který vám nejvíce vyhovuje. + +```texy +[Text odkazu](https://adresa.cz) // Styl známý z Markdownu +[Text odkazu | https://adresa.cz] // Styl známý z MediaWiki +text:[cílová URL nebo reference] // Jednoslovný odkaz +``` + +ID syntaxe `phrase/markdown`, `phrase/wikilink`, `phrase/quicklink` | [PhraseModule |configuration#phrasemodule] + + +Udržujte si pořádek s referencemi +--------------------------------- + +Při psaní delších textů může být nepohodlné vkládat dlouhé URL adresy přímo do odstavců – zhoršuje to čitelnost a přehlednost. Pro tyto případy má Texy **referenční odkazy**. + +V textu použijete pouze krátký, snadno zapamatovatelný název reference. A na konci dokumentu pak všechny tyto reference přehledně definujete. + +```texy +Doporučujeme si prostudovat "oficiální dokumentaci":[doc] a projít si "příklady syntaxe":[syntax]. +Celý projekt je postaven na [Nette]. + +​[doc]: https://texy.nette.org/cs/ "Dokumentace Texy!" +​[syntax]: https://texy.nette.org/cs/syntax +​[Nette]: https://nette.org +``` + +ID syntaxe `link/reference`, `link/definition` | [LinkModule |configuration#linkmodule] + + +Automatické odkazy +------------------ + +Kdykoli do textu napíšete URL adresu (začínající na `http://`, `https://`, `www.`) nebo e-mail, Texy ji automaticky rozpozná a převede na klikatelný odkaz. Nemusíte dělat vůbec nic. + +```texy +Náš web najdete na adrese www.example.com. +Pro podporu pište na support@example.com. +``` + +ID syntaxe `link/url`, `link/email` | [LinkModule |configuration#linkmodule] + + +Stylování odkazů +---------------- + +S [#modifikátory] můžete odkazům snadno přidávat další vlastnosti: + +```texy +"Externí odkaz .[external](Otevře se v novém okně){target:_blank}":https://google.com +``` + +Speciální třída `nofollow` přidá odkazu atribut `rel="nofollow"`, čímž dáváte vyhledávačům signál, aby tento odkaz nesledovaly. To se hodí například u odkazů v komentářích. + +```texy +"Odkaz, kterému nedůvěřuji .[nofollow]":https://example.com +``` + + +Automatické maskování e-mailů +----------------------------- + +Texy automaticky obfuskuje (maskuje) emailové adresy před spamboty: + +```latte +<a href="mailto:info@example.com">info@<!-- -->example.com</a> +``` + +Toto chování můžete vypnout: + +/--php +$texy->obfuscateEmail = false; +\-- + + +Přímé HTML +========== + +Texy je navržen tak, abyste HTML nemuseli psát vůbec. Ale co když narazíte na situaci, kdy je přímé vložení HTML značky jednodušší, nebo potřebujete vytvořit něco, na co syntaxe Texy nestačí? Žádný problém. Texy vám dává naprostou svobodu kombinovat oba světy. + +Můžete plynule přecházet mezi Texy syntaxí a čistým HTML, kdykoli se vám to hodí. + +```texy +Toto je **tučný text** v Texy a toto je <strong>tučný text</strong> pomocí HTML. + +<div class="info-box"> + <h3>Můžete vkládat i celé komplexní bloky</h3> +</div> +``` + +Možná si říkáte, že vkládání přímého HTML může být riskantní. Co když uděláte chybu nebo někdo vloží škodlivý kód? Texy na to myslí a funguje jako inteligentní filtr a pomocník: + +- **Opravuje chyby:** Texy zajistí, aby byl výsledný kód vždy validní a nerozbil vám stránku. +- **Hlídá bezpečnost:** Texy má ve výchozím stavu seznam povolených značek a jejich atributů. Pokud se v kódu objeví neznámá značka nebo potenciálně nebezpečný atribut (např. `onclick`), Texy ho bezpečně odstraní. Chrání tak váš web před XSS útoky. +- **Zajišťuje konzistentní výstup:** Bez ohledu na to, jaký HTML kód vložíte, Texy se postará, aby byl výsledek vždy správně strukturovaný (well-formed). + +Tento ochranný štít si můžete přizpůsobit. Pomocí konfigurace `$texy->allowedTags` můžete přesně definovat, které HTML značky a atributy jsou na vašem webu povoleny a které ne. + +Máte tak plnou kontrolu nad tím, jaké HTML mohou například redaktoři používat, a zajišťujete tak konzistenci a bezpečnost celého webu. Více informací naleznete v sekci "konfigurace":configuration#allowedtags. + +ID syntaxe `html/tag`, `html/comment` | [HtmlModule |configuration#htmlmodule] + + +Nadpisy +======= + +Texy vám nabízí dva elegantní a intuitivní způsoby, jak nadpisy vytvářet: **podtržené** a **ohraničené**. + + +Podtržené nadpisy +----------------- + +Tento styl připomíná psací stroj. Jednoduše pod nadpis vložte podtržení (alespoň 3 znaky). O důležitosti titulku rozhoduje podtrhávací znak. Od nejvyšší po nejnižší jsou to tyto: `#` `*` `=` `-` + +```texy +Toto je nejdůležitější nadpis celého dokumentu +​################################################ + +A toto je nadpis druhé úrovně +​****************************** +``` + +ID syntaxe `heading/underlined` | [HeadingModule |configuration#headingmodule] + + +Ohraničené nadpisy +------------------ + +Tento způsob je velmi rychlý na psaní. Text nadpisu "zabalíte" mezi znaky `#` nebo `=`. Zde o úrovni nadpisu rozhoduje **počet** použitých znaků (2 až 7). Čím více znaků, tím důležitější nadpis. + +```texy +=== Nejdůležitější nadpis (H1) + +== Méně důležitý (H2) + +# Ještě méně důležitý (H3) +``` + +Můžete použít ohraničení na obou stranách (pro lepší vizuální přehlednost) nebo jen na začátku. Texy si s oběma variantami poradí. + +ID syntaxe `heading/surrounded` | [HeadingModule |configuration#headingmodule] + + +Stylování nadpisů +----------------- + +Ke každému nadpisu můžete přidat [#modifikátory]. To vám umožní přiřadit mu konkrétní CSS třídu pro stylování nebo unikátní ID, na které pak můžete odkazovat. + +```texy +Nadpis s červenou barvou .[cerveny-nadpis] +​========================================== + +### Nadpis s unikátním ID pro odkazování .[#kontakt] +``` + + +Automatické kotvy pro snadnou navigaci +-------------------------------------- + +Nechcete vymýšlet ID pro každý nadpis ručně? Texy to umí udělat za vás! V konfiguraci můžete zapnout automatické generování ID pro všechny nadpisy. To je neuvěřitelně užitečné pro přímé odkazování na konkrétní sekce. + +```php +// Povolit automatické generování ID +$texy->headingModule->generateID = true; + +// Volitelně nastavit předponu pro generovaná ID (např. "sekce-") +$texy->headingModule->idPrefix = 'toc-'; +``` + +S tímto nastavením nadpis `## Moje kapitola` automaticky dostane například ID `id="toc-moje-kapitola"`, aniž byste museli cokoliv psát navíc. + + +Seznamy +======= + + +Odrážkové seznamy +----------------- + +Pro rychlý výčet položek, u kterých nezáleží na pořadí, se skvěle hodí odrážkový seznam. Stačí každý řádek začít pomlčkou `-`, hvězdičkou `*` nebo pluskem `+` a mezerou. Všechny tři znaky fungují stejně, takže si můžete vybrat ten, který je vám nejsympatičtější. + +```texy +Co je potřeba nakoupit: + +- Mléko +- Chleba +* Vejce ++ Máslo +``` + +ID syntaxe `list` | [ListModule |configuration#listmodule] + + +Číslované seznamy +----------------- + +Texy podporuje různé styly číslování: + +| `1.` | Arabské číslice (s tečkou) +| `1)` | Arabské číslice (se závorkou) +| `a)` | Malá písmena abecedy +| `A)` | Velká písmena abecedy +| `I)` | Římské číslice + +Kouzlo spočívá v tom, že se vůbec nemusíte starat o správné číslování. I když všechny řádky očíslujete jedničkou, Texy je automaticky přečísluje za vás. To je obrovská výhoda, když později potřebujete nějakou položku přidat, smazat nebo přesunout. + + +Vnořené a kombinované seznamy +----------------------------- + +Síla seznamů se naplno projeví, když je začnete kombinovat a vnořovat. Můžete tak vytvářet přehledné, víceúrovňové struktury. Vnoření vytvoříte jednoduše tak, že daný řádek odsadíte alespoň o **dvě mezery** (nebo jeden tabulátor). + +```texy +1) První kapitola + a) Podkapitola 1.1 + - První bod + - Druhý bod + b) Podkapitola 1.2 +2) Druhá kapitola + - Hlavní myšlenka + - Další poznámka +``` + + +Seznamy definic +--------------- + +Pro případy, kdy potřebujete vytvořit slovníček pojmů nebo přehledně vysvětlit několik termínů, je ideální definiční seznam. + +Na první řádek napište termín, který chcete definovat, a zakončete ho dvojtečkou. Na další řádky pište jeho definici, přičemž každý řádek odsaďte a začněte pomlčkou `-` + +```texy +HTML: + - Značkovací jazyk pro tvorbu webových stránek. + - Zkratka pro HyperText Markup Language. + +CSS: + - Jazyk pro popis způsobu zobrazení (stylování) stránek. + - Zkratka pro Cascading Style Sheets. +``` + +ID syntaxe `list/definition` | [ListModule |configuration#listmodule] + + +Stylování seznamů +----------------- + +Stejně jako u ostatních prvků v Texy, i seznamům můžete snadno přidávat [#modifikátory] pro změnu vzhledu. + +**Celý seznam:** Modifikátor napište na řádek **před** začátkem seznamu. + +```texy +.[barevny-seznam] +- První položka +- Druhá položka +``` + +**Jednotlivá položka:** Modifikátor přidejte na **konec** řádku dané položky nebo definičního termínu. + +```texy +- Běžná položka +- Tato položka je důležitá! .{font-weight: bold} +- Další běžná položka +``` + + +Obrázky +======= + +Základní syntaxe je velmi jednoduchá. Cestu k obrázku (ať už lokálnímu souboru, nebo URL adrese) stačí uzavřít do hranatých závorek s hvězdičkou: + +```texy +[* obrazek.jpg *] +[* https://domena.cz/logo.png *] +``` + +Často budete chtít, aby text obrázek obtékal. K tomu slouží jednoduché zarovnávací značky, které se vkládají před uzavírací závorku: + +```texy +[* obrazek.jpg <] Tento text bude plynule obtékat obrázek z pravé strany. + +[* obrazek.jpg >] V tomto případě bude text naopak obtékat obrázek z levé strany. + +[* velky-obrazek.jpg <>] +Tento text bude pokračovat až pod vycentrovaným obrázkem. +``` + +Správně vložený obrázek by měl mít i tzv. "alternativní text", který se zobrazí, pokud se obrázek nenačte. Pomocí [modifikátoru|#modifikátory] můžete přidat tento text i další prvky pro stylování. + +```texy +[* fotka-krajiny.jpg .(Krásná horská krajina při západu slunce)[main-photo] *] +``` + + +Rozměry obrázků +--------------- + +Texy umí u lokálních obrázků automaticky zjistit jejich rozměry (pokud je nastavena cesta `$texy->imageModule->fileRoot`) a doplnit je do HTML, což zrychluje načítání stránky. Pokud ale chcete rozměry nastavit ručně, máte několik možností: + +| `[* img.jpg 150x100 *]` | Přesná šířka 150px a výška 100px +| `[* img.jpg 150 *]` | Šířka bude 150px, výška se automaticky dopočítá se zachováním poměru stran +| `[* img.jpg ?x100 *]` | Výška bude 100px, šířka se automaticky dopočítá + + +Klikatelné obrázky +------------------ + +Chcete, aby se po kliknutí na malý náhled zobrazil velký obrázek? Nebo aby obrázek odkazoval na jinou stránku? Stačí za syntaxi obrázku přidat dvojtečku a cílovou URL. + +```texy +[* nahled.jpg *]:velky.jpg +[* logo-nette.png *]:https://nette.org +``` + +Pro galerie existuje i šikovná zkratka `::`. Ta automaticky vytvoří odkaz na stejný soubor umístěný na `$texy->imageModule->linkedRoot`. + + +Viditelný popisek pod obrázkem +------------------------------ + +Pokud chcete pod obrázek přidat viditelný popisek (např. jméno autora nebo popis scény), napište za něj tři hvězdičky `***` a text popisku. Texy z toho automaticky vytvoří sémanticky správnou HTML strukturu `<figure>` a `<figcaption>`. + +```texy +[* fotka.jpg <> *] *** Toto je popisek. Může obsahovat i **další formátování**. +``` + + +Udržujte si pořádek s referencemi +--------------------------------- + +Pokud v textu používáte jeden obrázek vícekrát nebo chcete mít všechny definice obrázků přehledně na jednom místě, můžete použít reference. V textu použijete jen zástupný název a na konci souboru pak definujete, co tento název znamená. + +```texy +V našem logu [* firemni-logo *] je vidět symbol naší vize. + +​[* firemni-logo *]: /images/logo.svg 200x50 .(Logo naší společnosti) +``` + +Tento přístup výrazně zpřehledňuje hlavní text a usnadňuje správu obrázků. + +ID syntaxe `image/definition` | [ImageModule |configuration#imagemodule] + + +Předformátovaný text +==================== + +V Texy můžete snadno vložit bloky kódu nebo jakýkoli předformátovaný text, u kterého chcete zajistit, aby se zobrazil přesně tak, jak ho napíšete – včetně všech mezer a konců řádků. To je ideální pro ukázky zdrojových kódů, logů nebo ASCII artu. + +Pro vložení takového bloku použijte ohraničení `/--` a `\--`: + +```texy +/-- +function hello() { + echo 'Hello World'; +} +\-- +``` + +Aby byl váš kód ještě čitelnější, můžete Texy sdělit, v jakém programovacím jazyce je napsaný a vytvořit si handler, který například obarví syntaxi, viz "ukázka":custom-handlers#syntax-highlighting. Stačí za úvodní značku `/--` přidat klíčové slovo `code` a název jazyka: + +```texy +/--code javascript +console.log('JavaScript'); +\-- + +/--code html +<div>Tohle je HTML kód</div> +\-- +``` + + +Obsahové bloky (divy) +===================== + +Texy umožňuje vytvářet obecné `<div>` bloky, díky kterým můžete snadno seskupovat obsah do logických celků a následně je stylovat:. + +Blok vytvoříte pomocí značek `/--div` a `\--`. Navíc můžete snadno přidat [#modifikátory]: + +```texy +/--div .[important] +## Důležité upozornění + +Tento text bude uzavřen v bloku `<div class="important">`. +Díky tomu ho můžete pomocí CSS nastylovat, aby byl výraznější. +\-- +``` + +Síla `<div>` bloků spočívá také v možnosti je vnořovat do sebe. Tím můžete vytvářet i složitější struktury přímo v Texy, aniž byste museli psát HTML ručně. + +```texy +/--div .[outer] + Toto je vnější blok. + + /--div .[inner] + A toto je vnořený, vnitřní blok. + \-- + + Zde jsme opět ve vnějším bloku. +\-- +``` +Díky této jednoduché syntaxi můžete udržovat svůj obsah přehledný a sémanticky správně strukturovaný. + + +Vypnutí formátování +=================== + +Někdy se může hodit Texy na chvíli "vypnout" a vložit kus textu, kde nemá Texy zpracovávat své značky. + +Pokud potřebujete vložit komplexnější HTML strukturu bez parsování Texy značek, použijte blok `/--html`: + +```texy +/--html +<em>Tento text bude zpracován jako HTML, takže bude kurzívou.</em> + +**Ale tyto hvězdičky Texy ignoruje, takže tučné nebudou.** +\-- +``` + +V případě, že chcete zobrazit text přesně tak, jak je napsán, a ignorovat veškeré značky (jak Texy, tak HTML), použijte blok `/--text`. Vše uvnitř tohoto bloku se zobrazí jako obyčejný text. + +```texy +/--text +<em>Tento text se zobrazí i se značkami, kurzívou ale nebude.</em> + +**Ani toto nebude tučné.** +\-- +``` + +Co když ale nechcete vypínat Texy pro celý blok textu, ale jen pro krátkou frázi uprostřed věty? Pro tyto případy existuje elegantní a rychlé řešení: obalte daný text do **dvojitých apostrofů** `''`: + +```texy +Pokud chcete ukázat, jak se píše tučný text, napíšete: Syntaxe je ''**tučný text**''. +``` + +Výsledkem nebude tučný text, ale doslova se vypíše řetězec `**tučný text**`. + + +Tabulky +======= + +Pro vytvoření tabulky začněte každý řádek znakem `|` a jednotlivé buňky oddělujte také tímto znakem. Texy si už samo pohlídá zarovnání a správné HTML. + +```texy +| Jan | Novák | Praha +| Eva | Svobodová | Brno +``` + +Výsledek bude přehledná a správně naformátovaná tabulka. + +ID syntaxe `table` | [TableModule |configuration#tablemodule] + + +Hlavička tabulky +---------------- + +Každá správná tabulka by měla mít hlavičku, která popisuje, co se v jednotlivých sloupcích nachází. Hlavičku vytvoříte tak, že ji od zbytku tabulky oddělíte řádkem obsahujícím pomlčky `-`. + +```texy +| Jméno | Věk | Město +|----------|-----|------- +| Jan | 25 | Praha +| Eva | 30 | Brno +``` + +Alternativně můžete definovat záhlaví pro jednotlivé řádky (například pokud máte v prvním sloupci popisky). Toho dosáhnete přidáním hvězdičky `*` hned za úvodní `|`. + +```texy +|* Jméno | Jan | Eva +|* Věk | 25 | 30 +|* Město | Praha | Brno +``` + + +Sloučení buněk +-------------- + +Někdy je potřeba spojit několik buněk dohromady, ať už ve sloupcích nebo v řádcích. + +**Sloučení sloupců:** Pro horizontální spojení buněk jednoduše vynechejte oddělovač a místo něj použijte zdvojenou svislou čáru `||`. Buňka napravo se tím sloučí s buňkou nalevo od ní. + +```texy +| Jméno || Věk +|---------------------------- +| Jan | Novák | 25 +``` + +**Sloučení řádků:** Pro vertikální spojení buněk použijte v buňce, kterou chcete připojit k té nad ní, symbol stříšky `^`. Ta Texy říká: "Tuto buňku spoj s tou nad ní." + +```texy +| Měsíc | Prodeje | +|---------|---------- +| Leden | 150 ks | +| Únor | ^| +| Březen | 210 ks | +``` + +V tomto příkladu bude buňka s prodeji pro leden a únor spojená. + +Takto lze sloučit několik buňek napříč řádky a sloupci: + +```texy +| First Name | Last Name | Age +|---------------------------- +| Bill || 50 +| ^| 52 +| Jim | Beam | 70 +``` + + +Stylování tabulek +----------------- + +Stejně jako u jiných prvků v Texy můžete i tabulkám a jejich částem přidávat [#modifikátory] pro změnu vzhledu (např. CSS třídy, styly nebo ID). + +**Celá tabulka:** Modifikátor pro celou tabulku umístěte na samostatný řádek těsně před ni. + +```texy +.[data-table table-striped] +| Hlavička 1 | Hlavička 2 +|------------|------------ +| data | data +``` + +**Jednotlivé řádky:** Chcete-li nastylovat konkrétní řádek, přidejte modifikátor na jeho konec. + +```texy +| Jméno | Stav +|-------|-------------- +| Petr | Schváleno +| Jana | Zamítnuto | .{background: #ffdddd} +``` + +**Jednotlivé sloupce:** Pro nastylování celého sloupce vložte modifikátor na začátek první buňky daného sloupce. + +```texy +| Jméno | .> Cena | Skladem +|----------------|-----------|--------- +| Produkt A | 1 200 Kč | Ano +| Produkt B | 850 Kč | Ne +``` + +**Konkrétní buňka:** Modifikátor pro jednu buňku napište přímo do ní, obvykle na konec jejího obsahu. + +```texy +| Úkol | Status +|----------------------|------------------------------------- +| Připravit podklady | Hotovo +| Zkontrolovat data | Probíhá .{color: orange; font-weight: bold} +``` + + +Citace +====== + +Potřebujete-li ve svém textu zdůraznit myšlenku někoho jiného, ocitovat zdroj nebo jen vizuálně oddělit blok textu, stačí začít řádek znakem `>`. + +```texy +> Toto je citace. Slouží ke zvýraznění důležité myšlenky nebo úryvku z jiného zdroje. +``` + +Citace nemusí být jen jeden odstavec. Pokud chcete pokračovat dalším odstavcem v rámci stejné citace, jednoduše vložte prázdný řádek, který také začíná znakem `>`. + +```texy +> Toto je první odstavec citace. Lorem ipsum dolor sit amet. +> +> A toto je druhý odstavec, který stále patří do stejné citace. +> Tímto způsobem můžete strukturovat i delší texty. +``` + +Texy dokonce podporuje vnořené citace, což se hodí, pokud citujete někoho, kdo sám někoho cituje. Pro každou další úroveň vnoření přidejte další znak `>`. + +```texy +> Toto je vnější, hlavní citace. +> +> > A toto je už vnořená citace druhé úrovně. +> +> Zde se text vrací zpět do hlavní citace. +``` + +Uvnitř citací můžete samozřejmě používat i další formátování, jako je **tučný text** nebo *kurzíva*. + + +Horizontální čáry +================= + +Někdy je potřeba text vizuálně rozdělit. K tomu skvěle slouží horizontální čára. Na samostatný řádek napište tři nebo více pomlček `---` nebo hvězdiček `***`. + +```texy +První část textu o nějakém tématu. + +*** + +Druhá část textu, která začíná po vizuálním oddělení. +``` + +Abyste vytvořili horizontální čáru, **musí jí předcházet prázdný řádek**. Pokud byste ji napsali hned pod text, Texy by si myslelo, že chcete vytvořit podtržený nadpis. + +ID syntaxe `horizline` | [HorizLineModule |configuration#horizlinemodule] + + +Typografie +========== + +Síla Texy nespočívá jen ve formátování, ale také v automatických typografických korekcích. Texy se postará o detaily, které dělají text profesionálním a dobře čitelným, a to vše podle českých typografických pravidel. Vy se tak můžete soustředit jen na obsah. + +**Uvozovky:** Nemusíte řešit, jak na klávesnici napsat správné typografické uvozovky. Texy to udělá za vás. + +Klasické ''"strojopisné uvozovky"'' automaticky převede na správné české „uvozovky“ a vnořené ‚uvozovky‘. Typ uvozovek závisí na nastavení locale: + +```php +$texy->typographyModule->locale = 'cs'; // české +$texy->typographyModule->locale = 'en'; // anglické +``` + +**Pomlčky a spojovníky:** Inteligentně rozpozná, kdy použít krátký spojovník (v dělených slovech), a kdy delší pomlčku – například v rozsazích (10–15) nebo mezi slovy. + +```texy +10-15 → 10–15 (en dash pro rozsahy) +česko-slovenský → česko-slovenský (spojovník zůstává) +slovo -- slovo → slovo – slovo (en dash mezi slovy) +slovo --- slovo → slovo — slovo (em dash) +``` + +**Nezlomitelné mezery**: Jednou z největších výhod je automatické vkládání pevných (nezlomitelných) mezer tam, kde je to potřeba. Tím zabraňuje, aby na konci řádku zůstala osamocená jednopísmenná slova (jako `k`, `s`, `v`, `z`), což je častý typografický prohřešek. + +```texy +// Vy napíšete: +Navštívil jsem hrad v Praze. + +// Texy zajistí, aby "v" nikdy nezůstalo na konci řádku: +Navštívil jsem hrad v Praze. +``` + +Stejně tak se postará o správné mezery v telefonních číslech nebo datech, aby se nezalamovala. + +```texy ++420 776 552 046 → +420 776 552 046 (všechny mezery pevné) +``` + +**Automatické symboly:** Texy vám usnadní i psaní často používaných symbolů. + +| Napíšete | Texy vygeneruje | Popis +|----- +| `...` | … | Výpustka +| `(c)` | © | Copyright +| `(r)` | ® | Registrovaná známka +| `(tm)` | ™ | Trademark +| `10 x 5` | 10 × 5 | Znak násobení +| `+-` | ± | Plus-mínus +| `<-` `->` `<->` | ← → ↔ | Šipky + +Díky těmto automatickým úpravám bude váš text vždy vypadat profesionálně, aniž byste museli znát složité klávesové zkratky nebo HTML entity. + + +Dělení dlouhých slov +-------------------- + +Znáte to – v textu se objeví dlouhé slovo, jako například "nejneobhospodařovávatelnějšími", a na úzké obrazovce mobilního telefonu rozbije celý layout stránky. Texy naštěstí nabízí elegantní řešení: dokáže do slova vložit neviditelné "měkké rozdělovníky" (`­`). Tyto rozdělovníky prohlížeči napoví, na kterých místech (mezi slabikami) může slovo bezpečně zalomit, pokud se na konec řádku nevejde. Pokud se slovo na řádek vejde celé, rozdělovníky zůstanou skryté a nic se nestane. + +```latte +nejneobhospoda­řovávatelnějšími +``` + +Díky tomu se váš text vždy krásně přizpůsobí jakékoliv šířce obrazovky bez nechtěného horizontálního posouvání. + +Protože se tato funkce nehodí pro všechny typy webů, je ve výchozím stavu vypnutá. Aktivovat ji můžete v konfiguraci: + +```php +$texy->allowed['longwords'] = true; + +// Nastavit minimální délku slova, od které se má dělit (např. 20 znaků) +$texy->longWordsModule->wordLimit = 20; +``` + +ID syntaxe `longwords` | [LongWordsModule |configuration#long-wordsmodule] + + +Emotikony +========= + +Texy umí automaticky převádět klasické textové smajlíky na grafické emotikony. Jednoduše napište smajlíka tak, jak jste zvyklí, a Texy se postará o zbytek. + +| Napíšete | Texy vygeneruje +|----- +| `:-)` | 🙂 +| `:-(` | ☹ +| `;-)` | 😉 +| `:-D` | 😀 +| `:-*` | 😘 + +Podle konfigurace může Texy tyto zkratky převádět buď na moderní Unicode emoji (jako v tabulce výše), nebo na malé obrázky (`<img>`). + +Aby se předešlo nechtěným převodům například v technických textech, je tato funkce ve výchozím nastavení vypnutá. Pokud ji chcete používat, stačí ji jednoduše povolit: + +```php +$texy->allowed['emoticon'] = true; +``` + +Více informací o dostupných emotikonech a možnostech nastavení naleznete v [konfiguraci EmoticonModule |configuration#emoticonmodul]. + +ID syntaxe `emoticon` | [EmoticonModule |configuration#emoticonmodule] diff --git a/texy/cs/try-settings.texy b/texy/cs/try-settings.texy new file mode 100644 index 0000000000..66be081ed6 --- /dev/null +++ b/texy/cs/try-settings.texy @@ -0,0 +1,55 @@ +Konfigurace dema +**************** + +Toto nastavení se používá v [demu | https://fiddle.nette.org/texy/]: + +/--php +$texy = new Texy\Texy; + +$texy->imageModule->root = '/images/'; +$texy->imageModule->linkedRoot = '/images/'; +$texy->headingModule->generateID = true; + +// syntax highlighting +$texy->addHandler('block', 'blockHandler'); +\-- + +Handler pro zvýrazňování syntaxe používá knihovnu Prism.js: + +/--php +function blockHandler( + Texy\HandlerInvocation $invocation, + string $blocktype, + string $content, + string $lang, + Texy\Modifier $modifier +): Texy\HtmlElement +{ + if ($blocktype !== 'block/code') { + // nothing to do + return $invocation->proceed(); + } + + $texy = $invocation->getTexy(); + $elPre = Texy\HtmlElement::el('pre'); + if ($modifier) { + $modifier->decorate($texy, $elPre); + } + $elPre->attrs['class'] = 'language-' . $lang; + $content = $texy->protect(htmlspecialchars($content), $texy::CONTENT_BLOCK); + $elPre->create('code', $content); + return $elPre; +} +\-- + +Po dokončení konverze se navíc v textu zamění některé znaky za entity, aby byly lépe patrné: + +/--php +$html = $texy->process($text); + +$html = str_replace( + ["\xc2\xa0", "\xc2\xad", "\xe2\x80\x93", "\xe2\x80\x94"], + [' ', '­', '–', '—'], + $html +); +\-- diff --git a/texy/en/@home.texy b/texy/en/@home.texy new file mode 100644 index 0000000000..27b8c786c9 --- /dev/null +++ b/texy/en/@home.texy @@ -0,0 +1,120 @@ +Texy! is sexy! +************** + +.[perex] +Texy is a **powerful and secure markup processor** for PHP that converts simple text into valid HTML. Unlike other markup languages, Texy isn't just another Markdown variant – it's a **fully configurable system** that you can adapt to virtually any syntax. + + +Why Texy? +========= + + +Security as a Priority +---------------------- + +Texy is designed with security in mind. It automatically **protects against XSS attacks**, validates URLs, and filters dangerous HTML tags. The built-in `safeMode()` is ideal for processing user-generated content in comments or forums. + +```php +Texy\Configurator::safeMode($texy); +// Texy is now safe for user-generated content +``` + + +Full Configurability +-------------------- + +Want to use Markdown syntax? Or need completely custom markup? **Texy can handle it.** You can: + +- Disable or enable any parts of the syntax +- Change default behavior using handlers +- Add entirely custom syntax elements +- Configure Texy to process Markdown or any other format + +```php +$texy = new Texy; +$texy->allowed['image'] = false; // disable images +$texy->allowed['phrase/strong'] = false; // disable bold text +``` + + +Advanced Typography +------------------- + +Texy provides **sophisticated typographic processing** that can be tailored to different languages. Depending on the configured locale, it automatically: + +- Inserts **non-breaking spaces** after single-letter prepositions and conjunctions +- Applies **word hyphenation** according to syllable rules +- Uses proper **typographic quotation marks** based on language conventions +- Applies proper **dash and hyphen distinction**: 10–15 (dash) vs. multi-word (hyphen) +- Adds **non-breaking spaces** in phone numbers: +420 776 552 046 + + +Valid and Well-Formed HTML +-------------------------- + +Texy always generates **valid HTML5 code**. It automatically corrects improperly nested tags, closes unclosed elements, and ensures proper document structure. The output is not only valid but also **beautifully formatted** with proper indentation. + + +What is Texy? +============= + +Texy is a **general-purpose markup text processor**. While it has its default syntax (similar to Markdown but much richer), you can completely change or extend it. + +**It's not just a parser** – Texy is a comprehensive system with modular architecture, where each module processes a specific part of the syntax (headings, links, images, tables...). Thanks to the handler system, you can intervene at any point in the processing and modify the result according to your needs. + + +Texy vs. Markdown +================= + +The basic syntax is similar, but Texy offers much more: + +|--------------------------- +| Feature | Markdown | Texy +|--------------------------- +| Bold text | `**text**` | `**text**` +| Italic | `*text*` or `_text_` | `*text*` or `//text//` +| Headings | `# Heading` | `# Heading` or underline +| Images | `![alt](url)` | `[* url *]` +| Tables | limited | full support including merging +| Modifiers | no | yes – `.{color:red}[class]` +| Typography | no | yes – quotes, dashes, spaces +| Word hyphenation | no | yes – by syllables +| Configurability | limited | complete – custom syntax +| Security | depends on impl. | built-in (safeMode) + +**Example of differences:** + +```texy +Markdown: +![Image](image.jpg) + +Texy: +[* image.jpg 300x200 .(Image caption)[photo] <] +``` + +Texy allows you to define dimensions, classes, alignment, and much more directly in the syntax. + + +When to Use Texy? +================= + +Texy is ideal for: + +**CMS systems** Need to safely process content from editors? Texy offers granular control over what users can use. + +**Blogs and documentation** Rich syntax for tables, images with captions, typography, and code with syntax highlighting. + +**Comments and discussion forums** SafeMode ensures users cannot insert dangerous code while still having text formatting available. + +**Projects with custom requirements** Need to embed YouTube videos? Special syntax for your macros? Custom markup language? With Texy, you can create it easily. + + +History +======= + +Texy was created by David Grudl **20 years ago** in 2004 as one of the first markup processors for PHP. Originally developed for **PHP 4**, it has undergone many updates throughout its long history and today fully leverages all the capabilities of **PHP 8**. + +Over two decades of active development mean a **proven and stable** library trusted by hundreds of projects. Texy is now a **mature solution** with extensive history, yet still actively maintained and modern. + + +{{maintitle: Texy – human friendy markup for PHP}} diff --git a/texy/en/@menu.texy b/texy/en/@menu.texy new file mode 100644 index 0000000000..66743bb1f1 --- /dev/null +++ b/texy/en/@menu.texy @@ -0,0 +1,6 @@ +- [home | @home] +- [syntax | syntax] +- [for developers | develop] +- "Playground .[link-external]":https://fiddle.nette.org/texy/ +- "API .[link-external]":https://api.nette.org/texy/ +- "GitHub .[link-external]":https://github.com/dg/texy diff --git a/texy/en/@meta.texy b/texy/en/@meta.texy new file mode 100644 index 0000000000..4ec8857a1e --- /dev/null +++ b/texy/en/@meta.texy @@ -0,0 +1 @@ +{{sitename: Texy Documentation}} diff --git a/texy/en/architecture.texy b/texy/en/architecture.texy new file mode 100644 index 0000000000..5e8bf97c11 --- /dev/null +++ b/texy/en/architecture.texy @@ -0,0 +1,425 @@ +Architecture and Principles +########################### + +.[perex] +Texy is a tool for converting text written in its own markup language into HTML. Unlike simple converters that process text linearly through a series of replacements, Texy uses a sophisticated system based on parsing, a modular architecture, and the gradual construction of a DOM tree. + +The basic processing flow consists of four main phases: + +1. Text preprocessing - normalization, adjustment of spaces and tabs, calling notification handlers for preparation +2. Parsing - recognizing syntaxes using regular expressions and gradually building the DOM tree +3. Post-processing - typographic adjustments, handling long words, well-forming HTML +4. Final assembly - converting the DOM tree into an HTML string + +The key difference from naive approaches is the separation of the syntax recognition phase from the processing phase. The parser first identifies where each syntactic construct is located in the text, and only then passes the found parts to individual modules for processing. This allows for nesting syntaxes and their gradual expansion. + +*Note: all classes are in the `Texy` namespace, so if the document mentions a class like `HtmlElement`, its full name is `Texy\HtmlElement`. Modules are in the `Texy\Modules` namespace* + + +Key Components +============== + +The Texy architecture consists of several main components, each with a clearly defined responsibility: + +The Texy class acts as the central orchestrator of the entire system. It contains references to all modules, manages registered syntaxes and handlers, maintains the processing state, and coordinates the individual conversion phases. It is the only place where the individual components are interconnected. + +**[Modules|#Moduly]** represent functional units responsible for specific areas of the markup language. Each module, upon its construction, registers the syntaxes it recognizes and the element handlers that process them. For example, PhraseModule handles inline formatting like bold or italic text, while TableModule processes tables. Modules are designed as separate, reusable units with their own configuration accessible through public properties. + +**[Parsers|#Parsery]** exist in two variants depending on the type of content being processed. BlockParser processes block structures like paragraphs, headings, lists, or tables. It goes through the text line by line, looking for the beginnings of block constructs and passing them to *syntax handlers*. LineParser handles inline syntaxes within lines - links, images, text formatting. Unlike BlockParser, it allows for nesting syntaxes and their gradual expansion. + + +Basic Terminology +================= + +To correctly understand how Texy works, it is necessary to distinguish between several key concepts that frequently appear in the documentation. + +**Syntax** refers to a named syntactic construct of the markup language. Each syntax has a unique name, for example, `phrase/strong` for bold text or `image` for images. The syntax name is used to enable or disable it in the `Texy::$allowed` array and is passed as a parameter to syntax handlers to distinguish which specific syntax was found. + +**Pattern** is a regular expression that defines what the syntax looks like in the text. The pattern is an implementation detail of the syntax - the author of the syntax must write a regex that recognizes it, but from the perspective of a Texy user, the syntax name and its meaning are more important. One module typically registers multiple syntaxes with different patterns. + +**Syntax handler** is a function called by the parser when it finds an occurrence of a syntax in the text. It receives the found text and returns an `HtmlElement` or a string, which is inserted in the original place. The syntax handler is where the decision is made about what to do with the found syntax - it typically invokes an element handler for the actual processing. + +**Element** is an item for which an HTML representation is generated. For example, `image` is an element for images, `linkURL` for links, `phrase` for inline formatting. Each element has its default element handler that takes care of standard processing. + +**Element handler** is a function registered for a certain type of element and called through the HandlerInvocation system. A characteristic feature is the use of the `proceed()` method, which allows delegating processing to the next handler in the chain or to the module's default handler. Element handlers are used to modify or replace the default behavior. + +**Notification handler** is a function called to notify about a certain event. Unlike element handlers, it does not return any value and cannot influence the processing result. It is used for data preparation, logging, or modifying the already created DOM tree. + +The difference between the various handlers is key to understanding the architecture. A syntax handler is tightly coupled with the parser and a specific pattern - it addresses the question of *what to do when the parser finds this pattern*. Element handlers are at a higher level of abstraction - they address the question of *how to process this type of element*, regardless of which specific syntax created it. + + +Overall Processing Flow +======================= + +When Texy receives input text, it goes through the following processing procedure. + +During preprocessing, the text is normalized. Line endings are unified to the Unix format, spaces are standardized, and tabs are optionally replaced with spaces. Subsequently, *notification handlers* registered for the `beforeParse` event are invoked. These handlers can perform data preparation, such as loading reference definitions or adjusting the configuration based on the text content. + +The parsing itself begins with the creation of a root `HtmlElement`, which represents the document. Texy then decides whether to process the text as a single line or as a complete document with block structures. In the case of block processing, a BlockParser is created, which sequentially goes through the text and looks for individual block constructs. + +LineParser works differently than BlockParser. It does not traverse the text linearly but progressively searches for the nearest occurrence of any registered syntax. When it finds one, it calls the corresponding syntax handler, which creates the appropriate HTML element. This element is inserted back into the text using special masking, and the parser continues. This allows it to find and process syntaxes nested inside already processed constructs. + +After parsing is complete, a full DOM tree representing the document's structure is created. Texy invokes notification handlers for the `afterParse` event, which can perform final modifications to the tree, such as adding identifiers to headings or building a table of contents. + +Post-processing occurs during the conversion of the DOM tree to an HTML string. Each element is recursively converted to HTML code, during which typographic adjustments like replacing quotes, dashes, or inserting non-breaking spaces are applied. Furthermore, HTML well-forming is performed - automatic closing of tags, correction of improperly nested elements, and formatting and indentation of the code. + +The final phase is decoding all masked parts back to HTML tags, removing helper markers, and assembling the resulting HTML string. + + +Syntax System +************* + +In Texy terminology, a syntax represents a named syntactic construct of the markup language. It is an abstract concept connecting several elements: a unique name, a regular expression for recognition, and a method of processing. The syntax name serves as an identifier throughout the system - it is used in the `Texy::$allowed` array for enabling or disabling, passed to handlers to distinguish the type of construct, and appears in documentation and configuration files. + +Syntax naming conventions follow two main patterns. Simpler syntaxes have a single-word name corresponding to their purpose, for example, `image`, `table`, or `script`. More complex areas use hierarchical naming with a slash, for example, `phrase/strong`, `phrase/em`, or `link/reference`. The slash serves to logically group related syntaxes and facilitates bulk operations with them. + + +Line Syntax +=========== + +Line syntaxes are used to recognize inline elements within lines of text. Typically, this includes formatting like bold or italic text, links, images, or inline code. A characteristic of line syntaxes is that they can be nested within each other, and the parser expands them sequentially. + +A line syntax is registered by calling `Texy::registerLinePattern()` with several parameters. The first is the syntax handler, i.e., the callback called upon finding a match. The second parameter is the regular expression defining the syntax's appearance in the text. The third parameter is the syntax name used throughout the system. An optional fourth parameter is another regex to test if it's even worth searching for the pattern - it's used for optimization to avoid running a complex pattern on text that definitely cannot match. + +The pattern as a regular expression must adhere to certain rules. It must not be anchored to the beginning of the text because it is searched for anywhere in the line. It should be as specific as possible to avoid false matches. + +Inline syntaxes within lines of text are processed by the [LineParser|#LineParser]. When it finds a match, it calls the appropriate syntax handler. This handler receives three parameters. The first is the LineParser instance, which provides access to the Texy object and other contextual information. The second parameter is an array with the results of the regex match, including sub-expressions. The third parameter is the syntax name, which is useful when the same callback handles multiple syntaxes. The handler must return either an `HtmlElement`, a string, or null if it refuses to process. + + +Block Syntax +============ + +Block syntaxes recognize multi-line block constructs such as headings, lists, tables, quotes, or special blocks. Unlike line syntaxes, block syntaxes never overlap - each line of text belongs to at most one block construct. + +Registering a block syntax uses `Texy::registerBlockPattern()` with three parameters: a syntax handler, a regular expression, and the syntax name. The pattern as a regular expression must adhere to certain rules. It must match from the beginning of the line and often contains an anchor for the end of the line. BlockParser automatically adds the `Am` modifiers, so the pattern should not contain them. + +Block syntaxes within a document are processed by the [BlockParser|#BlockParser]. When it finds a match, it calls the appropriate syntax handler. This handler receives similar parameters as with line syntaxes - a BlockParser instance, an array with the match, and the syntax name. It returns an `HtmlElement` representing the entire processed block, or null if it refuses processing. + + +Enabling and Disabling Syntax +============================= + +The `Texy::$allowed` array provides fine-grained control over which syntaxes are active in Texy. It is a simple yet powerful mechanism for configuring behavior without needing to change the modules' code. When you disable the `phrase/strong` syntax with this setting, the parser stops looking for the bold text construct: + +```php +$texy->allowed['phrase/strong'] = false; +``` + +The check is performed once at the beginning of parsing, so dynamically changing `$allowed` during processing has no effect. + +When constructing modules, a default value is set in `$allowed` for most syntaxes. Some syntaxes are enabled by default because they form the basis of the markup language. Others are disabled because they are advanced or potentially dangerous. For example, emoticons are disabled because not every document needs them, while basic formatting is enabled. + +Safe mode is a situation where you are processing untrusted input, such as user comments. You want to allow basic formatting but disable images, scripts, or HTML tags. `Texy\Configurator::safeMode()` sets `$allowed` for a safe combination of syntaxes. It typically disables image, figure, script, and HTML tags, but leaves links and formatting enabled. + + +Parsers +******* + + +Syntax Handler +============== + +As we mentioned in the previous section, LineParser or BlockParser goes through the text and looks for all registered patterns. When it finds a match, it calls the appropriate syntax handler and passes it information about the find - particularly an array with the results of the regex match. + +The syntax handler analyzes the found text and prepares the data for processing. It can extract parts of the text from regex groups, create helper objects like `Link` or `Image`, and parse modifiers. It also decides which element handler to invoke. It calls `Texy::invokeAroundHandlers()` with the element name and the prepared parameters. This begins their execution. The returned result is passed back to the syntax handler, which returns it to the parser. + + +Element Handler +=============== + +Element handlers implement the chain of responsibility pattern, which allows the final behavior to be composed from multiple layers. + +An element handler is registered by calling `Texy::addHandler()` with two parameters - the element name and the handler function. A single element name can have multiple handlers registered, which are then executed in order from the last registered to the first. + +The element name identifies the type of processing, for example, `phrase` for formatting, `image` for images, or `link` for links (note: this is different from syntax names). Sometimes, composite names like `linkReference` or `linkEmail` are used to distinguish different kinds of links. The names are more general than syntax names - while the `phrase/strong` syntax is a specific construct, the `phrase` element covers all kinds of inline formatting. + +Invoking an element handler uses the `Texy::invokeAroundHandlers()` method. This method receives the element name, the parser instance, and an array of parameters. It creates a HandlerInvocation object that encapsulates the entire chain of registered handlers. The first handler in the chain gets control and decides whether to call `HandlerInvocation::proceed()` to continue to the next handler or to return its own result. + +The HandlerInvocation object is key to understanding how the chaining works. It contains a stack of all handlers for the given element and the current position in this stack. When a handler calls `proceed()`, HandlerInvocation moves the position back one place in the stack and calls the next handler. If a handler calls `proceed()` with modified parameters, these new parameters are passed to all subsequent handlers. If a handler does not call `proceed()` at all, the chain is interrupted, and its return value becomes the result of the entire processing. + +The order of handler execution is from the last registered to the first. This means that a user-defined handler registered additionally gets control first and can decide whether to call the module's default handler at all. This order allows users to override the default behavior without needing to change the module's code. + +A typical use of an element handler looks like this. The handler checks the input parameters and decides if it wants to intervene in the processing. If so, it modifies the data, calls `proceed()` with the new parameters, and possibly modifies the returned result further. If the handler wants to completely replace the default processing, it creates its own result and returns it without calling `proceed()`. + + +Notification Handler +==================== + +Notification handlers represent a simpler, one-way communication mechanism. Unlike element handlers, they are not used for data transformation but for performing side actions. + +Registering a notification handler uses the same `Texy::addHandler()` method as element handlers. The difference is in how the handler is used - a notification handler returns no value and does not have access to HandlerInvocation. The first parameter is the event name. Descriptive names like `beforeParse` and `afterParse` are used for global events around parsing, or more specific ones like `afterTable`, `afterList`, `afterBlockquote` for events after a specific structure is created. The before/after prefix clearly indicates the timing of the event. + +Invoking notification handlers uses the `Texy::invokeHandlers()` method. This method simply calls all registered handlers in order and ignores their return values. Notification handlers receive the parameters passed during invocation but cannot change them for other handlers in the chain. + +Typical uses for notification handlers include several scenarios. A handler for the `beforeParse` event can load reference definitions from the text before parsing begins. A handler for `afterParse` can traverse the created DOM tree and add missing attributes or build a table of contents. Handlers like `afterTable` or `afterList` allow modules to perform final adjustments to the created structures. + +An important difference from element handlers is that notification handlers cannot prevent further processing. All registered handlers are always executed; none can break the chain. This is intended behavior - notification handlers are about side effects, not flow control. + + +LineParser +========== + +LineParser processes inline syntaxes within lines of text in a sequential manner that allows for nesting and complex interactions between syntaxes. + +The basic principle lies in finding the first occurrence of any syntax. In each iteration, it goes through all syntaxes and determines which one matches closest to the current position in the text. This syntax *wins* and is processed. If multiple syntaxes match at the same position, the one that was registered earlier wins - this is a priority based on registration order. + +When the parser finds the nearest match, it calls the corresponding syntax handler. This handler returns a result, which can be an `HtmlElement` or a string. This result then overwrites the found match in the text. + +Then, it searches again from the current position. This system ensures that the parser always sees the current state of the text. When we replace a match with new text that may contain other syntaxes, these syntaxes will be found in the next iteration. + +The `$again` property on the LineParser object is used for fine-grained control over whether the just-matched syntax should be searched for again at the same position after processing the current match. The default value is false, which says: *It no longer makes sense to look for this same syntax at this position. Move on.* + +The traversal ends when the parser reaches the end of the text or when no syntax has any more matches. The result is text where all recognizable syntaxes have been processed and replaced with their results, ready for final conversion. + + +Nesting +------- + +The ability to process nested syntaxes is one of the key features of LineParser and presents a fundamental challenge - how to prevent already processed HTML tags from being mistakenly interpreted as another syntax to be processed. + +When the parser processes text containing nested syntaxes, it first finds the outer construct. For example, in the text `"link **bold** text":URL`, the parser first finds the syntax for a link with quotes. The pattern for this syntax matches the entire string from the first quote to the colon and URL. The syntax handler creates an `HtmlElement` for the `<a>` tag, and the content `link **bold** text` is added as a child of the element. This string is inserted back into the text, and the parser continues searching for other syntaxes (`**bold**`, which represents bold text). + +But now it has a problem - there are also HTML tags in the text, which could match as the beginning of another syntax. The parser would start processing the already finished HTML tags as if they were part of the original text. + +We don't want the parser to see HTML tags. We need some way to distinguish already processed parts from parts waiting to be processed. The `Texy::protect()` method solves these problems in an elegant way - it replaces HTML tags with a unique placeholder composed of control characters - special bytes outside of printable ASCII. + +So, when an `HtmlElement` is converted to a string (using `toString()`), the result doesn't look like `<a href="...">link **bold** text</a>`, but for example, like `\x17\x18\x19\x17link **bold** text\x17\x18\x1A\x17`. + +Thus, during parsing, there are never actual HTML tags present in the text. Instead, there are only placeholders. But the inner text remains, and the parser sees it normally and can search for other syntaxes within it. This allows for gradual nesting - the outer syntax is masked, but its content is still accessible for inner syntaxes. + +At the end of processing, the `Texy::unProtect()` method goes through the resulting HTML string and replaces all placeholders with their actual values. Only at this moment do the actual HTML tags get into the output. + + +Masking Levels +-------------- + +Different types of content use different control characters for their placeholders, which allows syntaxes to selectively decide what they can contain. + +- `Patterns::CONTENT_MARKUP` denotes regular HTML markup like tags for formatting or links. It is the most common type and is used by most inline elements. The placeholder begins and ends with `\x17`. +- `Patterns::CONTENT_REPLACED` denotes content that has been replaced by something else, typically images or other replaced elements. It uses `\x16` as a marker. +- `Patterns::CONTENT_TEXTUAL` denotes text that has been escaped or otherwise treated to prevent processing. It is used for constructs like code or notexy, where we want to display the original text including markup symbols, not their interpretation. +- `Patterns::CONTENT_BLOCK` denotes block elements. It is the lowest level in the hierarchy. It uses `\x14` as a marker. + +The hierarchy of these types is not just a convention but has a practical consequence. The constant Patterns::MARK is defined as `\x14-\x1F`, i.e., a range covering all these types plus a reserve. Syntaxes use this constant in their patterns to exclude masked parts. + +Different syntaxes may have different requirements for what placeholders they can contain. A pattern that wants to see only plain text without any masked parts will use the exclusion `[^\x14-\x1F]`. This will reject all placeholders of all types. An example is the pattern for images - an image URL should not contain any HTML tags or blocks. + +A pattern that accepts lower levels but rejects higher ones will use a narrower range. For example, `[^\x17-\x1F]` will only reject `CONTENT_MARKUP` and above, but will accept `CONTENT_BLOCK`, `CONTENT_TEXTUAL`, and `CONTENT_REPLACED`. This is useful if we want to allow blocks but not inline markup. A practical example is TypographyModule, which performs typographic adjustments like replacing quotes or inserting non-breaking spaces. These adjustments should be applied to regular text, but not inside code blocks or preformatted text. + + +Syntax Collisions +----------------- + +A collision occurs when multiple syntaxes can match at the same position, and the system must choose one of them. + +A typical example is different lengths of the same symbol. The `phrase/strong+em` syntax uses three asterisks for a combination of bold and italics. The `phrase/strong` syntax uses two asterisks for bold text alone. The `phrase/em-alt` syntax uses one asterisk for italics. When the parser finds text starting with three asterisks, all three syntaxes can technically match. + +PhraseModule resolves this collision by registering syntaxes in order from longest to shortest. First, it registers `phrase/strong+em` with a pattern for three asterisks. Then `phrase/strong` with a pattern for two asterisks. Finally, `phrase/em-alt` with a pattern for one asterisk. Thanks to this order, when three asterisks are found, `phrase/strong+em` is processed first, and the shorter syntaxes don't get a chance. + +Another example is links in different formats. The `phrase/wikilink` syntax uses a pattern for `[text|url]`. The `link/reference` syntax uses a pattern for `[ref]`. Both start with an opening square bracket. If the text contains `[text|url]`, both patterns can technically start to match. + +The solution, again, is the specificity of the patterns. The pattern for `phrase/wikilink` is more specific - it requires a vertical bar inside the brackets. If the text contains a vertical bar, `phrase/wikilink` will match. If not, the pattern will fail, and `link/reference` gets a chance. The order of registration also plays a role here - `phrase/wikilink` should be registered before `link/reference`. + + +BlockParser +=========== + +BlockParser uses a fundamentally different approach to processing that reflects the nature of block constructs. The basic difference is the absence of intertwining. While LineParser allows syntaxes to be nested within each other and gradually expanded, BlockParser works with the assumption that each block is a separate unit. A single line or a group of lines belongs to at most one block. Blocks do not overlap, cross, or nest at the BlockParser level. + +BlockParser starts by finding all blocks, or rather their beginnings. The parser goes through all registered block syntaxes and finds all their occurrences. If multiple syntaxes match at the same position, the registration order is used - the earlier registered syntax takes precedence. + + +API for Syntax Handler +---------------------- + +BlockParser provides syntax handlers with an API for working with multi-line structures. + +The `BlockParser::moveBackward()` method is used to return to previous lines. It accepts the number of lines to go back. The parser moves its internal position towards the beginning of the text until it passes the specified number of line endings. This allows the callback to start reading from the beginning of the structure, even if the pattern matched in the middle or at the end. + +The `BlockParser::next()` method is used to read the next line matching a certain pattern. It accepts a regex pattern (it automatically adds the `Am` modifiers) and a reference to a variable for the match result. If the next line in the text matches the provided pattern, the method fills the result, moves the internal position past this line, and returns true. If the next line does not match, the method returns false, and the position does not change. + + +Modules +******* + +Modules are the basic organizational unit in the Texy architecture. Each module encapsulates the complete functionality for a specific area of the markup language. + +The primary responsibility of a module is to register syntaxes. In its constructor, the module calls `Texy::registerLinePattern()` or `registerBlockPattern()` for all the syntaxes it wants to process. This tells the parser: *When you find these patterns, call me.* The module thus defines which constructs in the text it recognizes. + +The second responsibility is the implementation of element handlers. The module registers handlers for the elements that its syntaxes invoke. These handlers contain the logic for converting the found constructs into HTML elements. The element handler decides what element to create, what attributes to set, and how to process the content. + +The third responsibility is to provide configuration. Modules have public properties that allow Texy users to modify the module's behavior without needing to change its code. For example, ImageModule has properties for setting the root path to images or the default alt text. + +The fourth responsibility is managing module-specific state. For example, HeadingModule keeps track of all found headings in the TOC array for building a table of contents. LinkModule manages a dictionary of references for links. This state is private to the module, and other parts of the system do not access it directly. + +Modules are designed as independent units. Each module can function on its own and should not depend on the implementation details of other modules. Communication between modules occurs through shared objects like `Link` or `Image`, not through direct method calls. + + +Structure of a Typical Module +============================= + +Most modules in Texy follow a similar structure that reflects their role in the system. + +The module inherits from the base class Module, which provides access to the Texy object via the protected property `$texy`. The module's constructor accepts a Texy instance and stores it. This allows the module to access the configuration and call methods on the Texy object. + +All initialization takes place in the constructor. The module sets the default values of its configuration properties, and possibly sets default values in the `Texy::$allowed` array for its syntaxes. Then it registers its syntaxes by calling `registerLinePattern()` or `registerBlockPattern()`. Each registration associates a pattern, a syntax handler, and a syntax name. Finally, the module registers its element handlers by calling `addHandler()`. + +Syntax handlers are methods of the module that the parser calls when it finds a syntax. These methods typically extract parts from the regex match, create helper objects, and invoke element handlers. The syntax handler decides which element handler to invoke and what parameters to pass. + +Element handlers are methods that implement the actual processing. They receive a HandlerInvocation object as the first parameter, followed by parameters specific to the given element. The element handler creates an `HtmlElement`, applies modifiers, processes the content, and returns the result. This is where the final form of the HTML is decided. + +Public properties serve as the interface for configuration. A Texy user can set these properties to customize the module's behavior. The properties are typically primitive types or arrays, not complex objects, to keep configuration simple. + + +Overview of Key Modules +======================= + +The standard distribution of Texy includes several modules covering various aspects of the markup language. + +- **PhraseModule** processes inline text formatting. It registers syntaxes for bold text, italics, underline, superscript, subscript, code, and more. All these syntaxes invoke a common handler for the `phrase` element, and the handler distinguishes which tag to create based on the syntax name. The module allows configuring which tags are used for each type of formatting. + +- **LinkModule** manages links in the document. It registers syntaxes for various link formats - explicit URLs, email addresses, references to defined links. It provides factory methods for creating `Link` objects and manages a dictionary of references. The module allows configuring the root for relative links, automatic `rel="nofollow"` for external links, and shortening of long URLs. + +- **ImageModule** processes images in a similar way to how LinkModule handles links. It registers syntax for inline images and manages a dictionary of references to defined images. It provides factory methods for creating `Image` objects and automatic detection of image dimensions. Configurable options include paths to images, default alt text, and CSS classes for alignment. + +- **HeadingModule** recognizes headings in various formats - underlined with dashes or equal signs, surrounded by hash marks. It collects all headings into a TOC array for a possible table of contents. It allows configuring the generation of IDs, the top level of headings, and the level balancing mode. + +- **ListModule** processes lists - unordered, ordered, and definition lists. It recognizes different types of bullets and automatically detects nesting based on indentation. It allows configuring which characters serve as bullets and what HTML lists to generate. + +- **TableModule** is one of the most complex modules. It recognizes tables with headers, bodies, captions, and supports colspan and rowspan. It processes modifiers for both rows and cells. + +- **BlockModule** processes special blocks delimited by `/--` and `\--`. It supports various block types - code for code, html for direct HTML, div for a generic container. It allows users to define custom handlers for their own block types. + +- **TypographyModule** performs post-processing for typographic adjustments. It replaces three dots with an ellipsis, double dashes with an en-dash, straight quotes with typographic ones, and inserts non-breaking spaces. It operates at the level of the final string between block elements. + +- **HtmlOutputModule** formats the final HTML output. It ensures well-formed HTML by automatically closing tags, correcting incorrect nesting, indenting the code, and wrapping long lines. It allows configuring the indentation level and line width. + + +Interaction Between Modules +=========================== + +Although modules are designed to be independent, in some cases they need to cooperate. + +Shared objects are the main communication mechanism. A `Link` object created by LinkModule can be passed to ImageModule to create an image link. An `Image` object created by ImageModule can be passed to FigureModule to create an image with a caption. These objects encapsulate all necessary information and provide a common interface. + +The reference system allows separating definition from use. LinkModule provides `addReference()` and `getReference()` methods for managing a dictionary of named links. A user can define a reference in one part of the document and use it in another. ImageModule has an analogous system for image references. Modules using references call factory methods that themselves check whether it is a reference or a direct value. + +Element handlers can call other element handlers. When PhraseModule processes a `phrase/span` with a link, it creates a `Link` object and calls the LinkModule's element handler to create the link. This delegates the responsibility for creating and configuring the link to the specialized module. + +Relationships between modules are typically one-sided. PhraseModule knows about LinkModule and ImageModule because it creates links and images. But LinkModule and ImageModule do not know about PhraseModule. This keeps dependencies simple and allows for easy replacement or extension of modules. + + +DOM Representation +****************** + +`HtmlElement` represents a single node in the DOM tree and provides an interface for its manipulation and processing. + +The basic structure of an element includes a tag name, an associative array of attributes, and an array of children. The children can be other `HtmlElement` instances or simply text strings. This combination allows for representing any HTML structure. + +The element name is set and retrieved via the `setName()` and `getName()` methods. A special value of null as the name means a transparent element, which has no tags, only its content. + +Attributes are publicly accessible via the `$attrs` property as an associative array. Values can be strings, numbers, booleans, or arrays. A boolean `true` means an attribute without a value (like `checked`), while `false` or `null` means the attribute will not be rendered at all. If the value is an array, the different elements are joined according to the attribute type - for `class` with spaces, for `style` with semicolons. The `setAttribute()` method sets the value of an attribute. The `getAttribute()` method returns the value of an attribute or null. + +Children are managed through several methods. The `add()` method adds a child to the end. The `insert()` method inserts a child at a specified position, optionally replacing an existing child. The `create()` method creates a new `HtmlElement` as a child and returns it for further manipulation. The `removeChildren()` method removes all children. + +The element implements the ArrayAccess interface, so children can be worked with like an array. The notation `$el[0]` returns the first child, `$el[0] = $child` sets the first child. This approach is convenient for quick manipulation of specific children. + +The `toString()` method recursively traverses the element and its children and builds a string representation. HTML tags are immediately masked using `Texy::protect()`, so a placeholder is inserted into the result instead of actual HTML characters. + +The `toHtml()` and `toText()` methods return the unmasked result including post-processing. + + +Parsing Content +=============== + +`HtmlElement` can recursively parse its content, allowing for the gradual building of the DOM tree. + +The `parseLine()` method is used to parse inline syntaxes in a string. It creates a new instance of LineParser with the current element as the container. It calls `parse()` on the parser with the provided text. LineParser sequentially finds and processes all inline syntaxes, and the resulting elements or strings are added as children of the current element. The method returns the used LineParser for possible further use. + +The `parseBlock()` method parses text as block content. It creates a BlockParser and calls `parse()` on it. BlockParser finds all block constructs in the text, processes them, and adds them as children of the element. Text between blocks is processed as paragraphs, which internally use LineParser. The method accepts a boolean parameter indicating whether the text comes from an indented block, which affects the processing of paragraphs. + +These parsing methods allow for recursive processing. A syntax handler can create an element, set its basic properties, and then call `parseLine()` or `parseBlock()` to process the content. The result is that the element's content goes through the same parsing process as the main document, including syntax recognition and handler invocation. + + +Validation +========== + +`HtmlElement` provides mechanisms for validating attributes and content according to the HTML DTD (Document Type Definition). + +The DTD is a static array defining for each HTML tag which attributes are allowed and what content it can contain. Texy loads the DTD from a file upon initialization and stores it in a static array. The DTD structure maps a tag name to a pair - an array of allowed attributes and an array of allowed content. + +The `validateAttrs()` method checks the element's attributes against the DTD. For a given tag, it gets the list of allowed attributes. It goes through all the element's attributes and removes those that are not on the list. Special cases are attributes starting with `data-` or `aria-`, which are allowed if a placeholder entry `data-*` or `aria-*` is in the DTD. + +This validation is typically called when applying modifiers with the `decorate()` method. It ensures that even if a user specifies a modifier with an invalid attribute for a given tag, the attribute does not get into the final HTML. This is important for security and HTML correctness. + +The `validateChild()` method checks whether a given child can be the content of the element. It accepts a child (`HtmlElement` or a tag name) and the DTD. If the element is defined in the DTD, the method checks if the child is in the list of allowed content. If so, it returns true. If not, it returns false. + +This validation can be used when dynamically building a DOM tree to ensure a correct structure. For example, a paragraph element must not contain block elements, so `validateChild()` would refuse to add a `div` into a `p`. In practice, Texy uses this validation to a limited extent, as the structure generated by the modules is typically correct by design. + +The combination of `validateAttrs()` and `validateChild()` provides a mechanism for ensuring valid HTML, even if the input contains untrusted data or poorly formed constructs. Texy can be configured for strict validation or can disable validation for maximum flexibility. + + +Modifiers +********* + +Modifiers provide a way to add additional attributes, classes, styles, and alignment to elements without having to write direct HTML. + +The basic format of a modifier is a dot followed by a combination of different parts in round, square, and curly brackets: `.(title)[class1 class2 #id]{style:value}<align>^valign`. The entire modifier is written before or at the end of the construct to which it applies. For example, `"**text** .(Important)[highlight]{color:red}"` creates bold text with the class `highlight`, red color, and a title attribute "Important". + +Round brackets contain the title attribute or alt text. The text inside is used as the value of the title attribute on the resulting element. If the element is an image, it can be used as alt text. Inside the round brackets, it is possible to escape a bracket with a backslash. + +Square brackets contain CSS classes and optionally an ID. Classes are written as words separated by spaces. An ID is written with a hash prefix. For example, `[main-content selected #article-5]` sets two classes and one ID. If an ID is specified multiple times, the last one is used. + +Curly brackets contain CSS styles or HTML attributes. Styles are written in the standard CSS format `property:value`. Multiple styles are separated by semicolons. Some properties are recognized as HTML attributes - for example, `{href:url}` is converted to an `href` attribute, not a CSS style. This allows setting attributes that cannot be expressed otherwise. + +Alignment is specified using special characters. `<` means left, `>` right, `=` for justify, `<>` for center. Vertical alignment uses `^` for top, `-` for middle, and `_` for bottom. These shortcuts are converted to either CSS classes or inline styles depending on the configuration. + +The parts of the modifier can be in any order, and some can be omitted. A modifier containing only classes `.[highlight]`, only a title `.(Note)`, or only a style `.{color:blue}` is valid. The parser recognizes the individual parts by their delimiting characters. + + +Modifier Class +============== + +The `Modifier` class is used to parse and store information from a modifier. + +An instance of `Modifier` is typically created by a syntax handler, which passes the modifier text extracted from a regex match to the constructor. The constructor calls the `setProperties()` method, which parses the text and populates the object's properties. + +Public properties contain the individual parts of the modifier. The `$id` property contains the element's ID as a string or null. The `$classes` property is an associative array where keys are class names and values are true. The `$styles` property is an associative array mapping CSS properties to values. The `$attrs` property is an associative array with HTML attributes that are not styles or classes. + +Two special properties, `$hAlign` and `$vAlign`, contain the horizontal and vertical alignment as strings `left`, `right`, `center`, `justify` or `top`, `middle`, `bottom`. These values are later converted to CSS classes or styles according to the Texy configuration. + +The `$title` property contains the text from the round brackets, which is used as the title attribute or alt text for images. The text is automatically unescaped from HTML entities and stripped of escaped brackets. + + +Application to Elements +======================= + +A `Modifier` object is applied to an `HtmlElement` using the `Modifier::decorate()` method. + +The `decorate()` method accepts a Texy instance and an `HtmlElement` as parameters. It sequentially applies the individual parts of the modifier to the element, taking into account the Texy configuration, which may prohibit or restrict some parts. + +The application of attributes checks which attributes are allowed for the given tag according to the `Texy::$allowedTags` configuration. If all attributes are allowed, all attributes from the `Modifier` are copied to the element. If only a list of specific attributes is allowed, only those that are on the list are copied. + +The title attribute is always applied if it is set, but the text undergoes typographic post-processing to replace quotes and other adjustments. + +The application of classes and ID checks the `Texy::$allowedClasses` configuration. If all classes are allowed, all classes from the `Modifier` are added to the element, and the ID is set. If only a list of specific classes is allowed, only those that are on the list are added. The ID is added only if a string starting with a hash is on the allowed list. + +The application of styles proceeds similarly, with a check of `Texy::$allowedStyles`. Allowed CSS properties are added to the element's style attribute. If the element already had some styles, the modifier's styles are added or overwrite existing ones. + +Alignment is applied either as a CSS class or an inline style. If a mapping is configured in Texy's `Texy::$alignClasses` for the given alignment type, the corresponding CSS class is added. If not, an inline style with the `text-align` or `vertical-align` property is added. + +The result is that the element has all the attributes, classes, styles, and other properties from the modifier, but only those that are allowed by the current Texy configuration. This ensures safety when processing untrusted input. + + +Propagation of Modifiers +======================== + +Modifiers pass through the system in several phases, maintaining flexibility and allowing for modifications at different levels. + +The syntax handler extracts the modifier text from the regex match and creates a new `Modifier` instance, populating its properties. + +The `Modifier` object is passed as a parameter to element handlers. The handler receives the already parsed object, not the raw text. This allows the handler to easily access the individual parts of the modifier - classes, styles, alignment. The handler can modify the modifier before application, for example, by adding more classes or changing styles. + +The element handler creates an `HtmlElement` and passes it to the `Modifier::decorate()` method. At this point, the modifier is applied to the element. The `decorate()` method checks the Texy configurations and ensures that only allowed parts are applied. + +In some cases, a module combines multiple modifiers. For example, TableModule parses modifiers at the table, row, and cell levels. A cell's modifier is actually a clone of the column's modifier, to which additional modifications from the specific cell's modifier are then applied. This allows for default styles for an entire column with the possibility of overriding them in individual cells. diff --git a/texy/en/configuration.texy b/texy/en/configuration.texy new file mode 100644 index 0000000000..eee1a1a890 --- /dev/null +++ b/texy/en/configuration.texy @@ -0,0 +1,719 @@ +Configuration +************* + +.[perex] +A complete guide to configuring Texy. Learn how to control all modules, set up security, and customize Texy to your needs. + +Texy is configured using **public properties** of the main `Texy\Texy` class and its **modules**. Each module is responsible for processing a specific part of the syntax (images, links, headings...). + +Basic approach: + +```php +$texy = new Texy\Texy; + +// Configuration of the main class +$texy->allowedTags = Texy\Texy::NONE; + +// Configuration of a module +$texy->imageModule->root = '/images/'; +``` + + +Texy\Texy Class .[#texy-class] +============================== + +The main class contains global settings and properties affecting the entire processing. + + +Allowed Syntax ($allowed) .{toc: $allowed} +------------------------------------------ + +The `$allowed` array controls which parts of Texy syntax are active: + +```php +// Default: all syntax features allowed (except emoticons) +$texy->allowed['image'] = true; +$texy->allowed['emoticon'] = false; + +// Disable images +$texy->allowed['image'] = false; + +// Disable HTML tags in input +$texy->allowed['html/tag'] = false; +$texy->allowed['html/comment'] = false; + +// Disable various types of links +$texy->allowed['link/reference'] = false; +$texy->allowed['link/email'] = false; +$texy->allowed['link/url'] = false; +``` + +**Complete list of syntax features:** + +|--- +| Key | Default | Description +|--- +| `image` | `true` | Images `[* img.jpg *]` +| `figure` | `true` | Images with caption +| `link/reference` | `true` | References `[ref]` +| `link/email` | `true` | Email addresses +| `link/url` | `true` | Automatic URLs +| `link/definition` | `true` | Reference definitions +| `heading/underlined` | `true` | Underlined headings +| `heading/surrounded` | `true` | Surrounded headings +| `horizline` | `true` | Horizontal lines +| `blockquote` | `true` | Quotes +| `list` | `true` | Lists +| `list/definition` | `true` | Definition lists +| `table` | `true` | Tables +| `phrase/strong` | `true` | Bold text `**text**` +| `phrase/em` | `true` | Italic `//text//` +| `phrase/em-alt` | `true` | Italic `*text*` +| `phrase/code` | `true` | Code ```text``` +| `phrase/ins` | `false` | Inserted text `++text++` +| `phrase/del` | `false` | Deleted text `--text--` +| `phrase/sup` | `false` | Superscript `^^text^^` +| `phrase/sub` | `false` | Subscript `__text__` +| `html/tag` | `true` | HTML tags in input +| `html/comment` | `true` | HTML comments +| `emoticon` | `false` | Emoticons `:-)`, `:-(` +| `blocks` | `true` | Blocks `/-- \--` +| `typography` | `true` | Typographic adjustments +| `longwords` | `true` | Breaking long words + + +Allowed HTML Tags ($allowedTags) .{toc: $allowedTags} +----------------------------------------------------- + +Controls which HTML tags are allowed in output (and input): + +```php +// Default: all valid HTML5 tags allowed +$texy->allowedTags = Texy\Texy::ALL; + +// Disable all HTML tags +$texy->allowedTags = Texy\Texy::NONE; + +// Allow only specific tags +$texy->allowedTags = [ + 'strong' => [], // <strong> without attributes + 'a' => ['href', 'title'], // <a> with attributes + 'img' => Texy\Texy::ALL, // <img> with any attributes +]; +``` + +**Formats:** +- `Texy::ALL` – all tags allowed +- `Texy::NONE` – no tags allowed +- Array – allowed tags as keys, allowed attributes as values + + +Allowed CSS Classes ($allowedClasses) .{toc: $allowedClasses} +------------------------------------------------------------- + +Controls which CSS classes and IDs can be used: + +```php +// Default: all classes and IDs allowed +$texy->allowedClasses = Texy\Texy::ALL; + +// Disable classes and IDs +$texy->allowedClasses = Texy\Texy::NONE; + +// Allow specific classes and IDs +$texy->allowedClasses = [ + 'highlight', + 'important', + '#main', // IDs start with # + '#sidebar', +]; +``` + +Usage: +```texy +Text with class .[highlight] + +Text with ID .{toc: main} +``` + + +Allowed CSS Styles ($allowedStyles) .{toc: $allowedStyles} +---------------------------------------------------------- + +Controls which inline CSS properties can be used: + +```php +// Default: all styles allowed +$texy->allowedStyles = Texy\Texy::ALL; + +// Disable inline styles +$texy->allowedStyles = Texy\Texy::NONE; + +// Allow specific CSS properties +$texy->allowedStyles = [ + 'color', + 'background-color', + 'font-size', +]; +``` + +Usage: +```texy +Text with color .{color: red} +``` + + +CSS Classes for Alignment ($alignClasses) .{toc: $alignClasses} +--------------------------------------------------------------- + +As an alternative to inline styles `style="text-align:left"`, you can use CSS classes: + +```php +// Default: empty array (uses inline styles) +$texy->alignClasses = [ + 'left' => null, + 'right' => null, + 'center' => null, + 'justify' => null, + 'top' => null, + 'middle' => null, + 'bottom' => null, +]; + +// Set classes +$texy->alignClasses['left'] = 'text-left'; +$texy->alignClasses['right'] = 'text-right'; +$texy->alignClasses['center'] = 'text-center'; +``` + +Usage: +```texy +Text aligned to the left . + +Text aligned to the right .> +``` + +With `alignClasses` set, it generates `<p class="text-left">` instead of `<p style="text-align:left">`. + + +Additional Properties +--------------------- + +```php +// Merge lines into paragraphs (default: true) +$texy->mergeLines = true; + +// Tab width (default: 8) +$texy->tabWidth = 8; + +// Obfuscate emails from bots (default: true) +$texy->obfuscateEmail = true; + +// Remove soft hyphens (default: true) +$texy->removeSoftHyphens = true; + +// Element for non-textual paragraphs (default: 'div') +$texy->nontextParagraph = 'div'; +``` + + +Modules +======= + +Each module processes a specific part of the syntax. Modules are accessible as public properties of the `Texy\Texy` class. + + +HeadingModule +------------- + +Processes headings (both underlined and surrounded). + +```php +// Top heading level (default: 1) +$texy->headingModule->top = 1; // <h1> + +// Generate automatic IDs (default: false) +$texy->headingModule->generateID = true; + +// Prefix for generated IDs (default: 'toc-') +$texy->headingModule->idPrefix = 'section-'; + +// More characters = higher heading? (default: true) +$texy->headingModule->moreMeansHigher = true; + +// Balancing mode (default: DYNAMIC) +$texy->headingModule->balancing = Texy\Modules\HeadingModule::DYNAMIC; +``` + +After processing: + +```php +// First heading (for <title>) +echo $texy->headingModule->title; + +// Table of Contents +print_r($texy->headingModule->TOC); +``` + + +PhraseModule +------------ + +Processes inline formatting (bold, italic, links within text...). + +```php +// HTML tags for individual phrases (default: see below) +$texy->phraseModule->tags = [ + 'phrase/strong' => 'strong', + 'phrase/em' => 'em', + 'phrase/code' => 'code', + // ... more +]; + +// Allow links in phrases (default: true) +$texy->phraseModule->linksAllowed = true; +``` + + +LinkModule +---------- + +Processes links, references, and URLs. + +```php +// Root path for links (default: '') +$texy->linkModule->root = '/articles/'; + +// CSS class for image links (default: null) +$texy->linkModule->imageClass = 'image-link'; + +// Always add rel="nofollow" (default: false) +$texy->linkModule->forceNoFollow = false; + +// Shorten URLs to a more readable form (default: true) +$texy->linkModule->shorten = true; +``` + +**References:** + +```php +// Add a reference +$link = new Texy\Link('https://example.com'); +$link->modifier->title = 'Example page'; +$link->label = 'Example'; +$texy->linkModule->addReference('example', $link); +``` + +Usage: +```texy +Link to [example] +``` + + +ImageModule +----------- + +Processes images. + +```php +// Root path for images (default: 'images/') +$texy->imageModule->root = '/assets/images/'; + +// Root path for linked images (default: 'images/') +$texy->imageModule->linkedRoot = '/assets/images/full/'; + +// Physical path on disk (to determine dimensions) +$texy->imageModule->fileRoot = __DIR__ . '/public/images/'; + +// CSS class for floating images (default: null) +$texy->imageModule->leftClass = 'float-left'; +$texy->imageModule->rightClass = 'float-right'; + +// Default alternative text (default: '') +$texy->imageModule->defaultAlt = 'Image'; +``` + +**References:** + +```php +// Add a reference +$image = new Texy\Image; +$image->URL = 'photo.jpg'; +$image->modifier->title = 'Photo'; +$texy->imageModule->addReference('photo', $image); +``` + + +FigureModule +------------ + +Processes images with captions. + +```php +// HTML element (default: 'div') +$texy->figureModule->tagName = 'figure'; + +// CSS class (default: 'figure') +$texy->figureModule->class = 'photo-figure'; + +// Classes for floating images (default: null) +$texy->figureModule->leftClass = 'figure-left'; +$texy->figureModule->rightClass = 'figure-right'; + +// Offset for width calculation (default: 10) +$texy->figureModule->widthDelta = 20; + +// Require caption (default: true) +$texy->figureModule->requireCaption = true; +``` + + +ListModule +---------- + +Processes bulleted, numbered, and definition lists. + +```php +// Patterns for list bullets (default: see source code) +$texy->listModule->bullets = [ + '*' => ['\*[\ \t]', 0, ''], + '-' => ['[\x{2013}-](?![>-])', 0, ''], + // ... more +]; +``` + + +TableModule +----------- + +Processes tables. + +```php +// CSS classes for rows (default: null) +$texy->tableModule->oddClass = 'odd'; +$texy->tableModule->evenClass = 'even'; +``` + +*Note: `oddClass` and `evenClass` are deprecated.* + + +HorizLineModule +--------------- + +Processes horizontal lines. + +```php +// CSS classes by type (default: null) +$texy->horizLineModule->classes = [ + '-' => 'hr-line', + '*' => 'hr-star', +]; +``` + + +TypographyModule +---------------- + +Processes typographic adjustments. + +```php +// Locale (default: 'cs') +$texy->typographyModule->locale = 'en'; +``` + +**Supported locales:** +- `cs` – Czech quotes „text" and ‚text' +- `en` – English quotes "text" and 'text' +- `fr` – French quotes «text» and ‹text› +- `de` – German quotes „text" and ‚text' +- `pl` – Polish quotes „text" and ‚text' + + +LongWordsModule +--------------- + +Breaks long words using `­`. + +```php +// Maximum word length (default: 20) +$texy->longWordsModule->wordLimit = 25; +``` + + +EmoticonModule +-------------- + +Replaces emoticons with images or Unicode characters. + +```php +// CSS class (default: null) +$texy->emoticonModule->class = 'emoji'; + +// Path to images (default: null = uses imageModule->root) +$texy->emoticonModule->root = '/images/smilies/'; +$texy->emoticonModule->fileRoot = __DIR__ . '/public/smilies/'; + +// Emoticon definitions (default: basic set) +$texy->emoticonModule->icons = [ + ':-)' => '🙂', + ':-(' => '☹', + ';-)' => '😉', + // ... or paths to images + ':cool:' => 'cool.gif', +]; +``` + + +HtmlModule +---------- + +Processes HTML tags and comments in the input text. + +```php +// Display HTML comments in output (default: true) +$texy->htmlModule->passComment = true; +``` + + +HtmlOutputModule +---------------- + +Formats the output HTML. + +```php +// Format output with indentation (default: true) +$texy->htmlOutputModule->indent = true; + +// Base indentation level (default: 0) +$texy->htmlOutputModule->baseIndent = 0; + +// Maximum line width (default: 80) +$texy->htmlOutputModule->lineWrap = 100; + +// Preserve whitespace in these elements (default: list shown) +$texy->htmlOutputModule->preserveSpaces = [ + 'textarea', 'pre', 'script', 'code', +]; +``` + + +ScriptModule +------------ + +Processes `{{macro}}` calls. + +```php +// Argument separator (default: ',') +$texy->scriptModule->separator = ';'; +``` + + +Texy\Configurator Class .{toc: Texy\Configurator} +================================================= + +Ready-made configuration sets for common use cases. + + +safeMode() – Safe Mode .{toc: safeMode()} +----------------------------------------- + +Configuration for processing **untrusted content** from users. + +```php +Texy\Configurator::safeMode($texy); +``` + +**What it does:** +- Disables classes and IDs (`$allowedClasses = NONE`) +- Disables inline styles (`$allowedStyles = NONE`) +- Allows only safe HTML tags: + +```php +[ + 'a' => ['href', 'title'], + 'abbr' => ['title'], + 'b' => [], + 'br' => [], + 'cite' => [], + 'code' => [], + 'em' => [], + 'i' => [], + 'strong' => [], + 'sub' => [], + 'sup' => [], + 'q' => [], + 'small' => [], +] +``` + +- Filters URL schemes (only `http:`, `https:`, `ftp:`, `mailto:`) +- Disables images +- Disables reference definitions +- Disables HTML comments +- Adds `rel="nofollow"` to all links + + +disableLinks() – Disable Links .{toc: disableLinks()} +----------------------------------------------------- + +Disables all types of links. + +```php +Texy\Configurator::disableLinks($texy); +``` + +**What it does:** +- Disables all types of links (`link/reference`, `link/email`, `link/url`, `link/definition`) +- Disables links in phrases (`phraseModule->linksAllowed = false`) +- Removes `<a>` from allowed tags + + +disableImages() – Disable Images .{toc: disableImages()} +-------------------------------------------------------- + +Disables all types of images. + +```php +Texy\Configurator::disableImages($texy); +``` + +**What it does:** +- Disables images (`image`, `figure`, `image/definition`) +- Removes `<img>`, `<object>`, `<embed>`, `<applet>` from allowed tags + + +Security +======== + +Texy is designed with security in mind. It automatically protects against common attacks. + + +Protection Against XSS +---------------------- + +Cross-Site Scripting (XSS) is an attack where an attacker injects malicious JavaScript into a page. + +**Examples of attacks that Texy will block:** + +```texy +Attack attempt: <script>alert('XSS')</script> + +Attack attempt: <img src=x onerror="alert('XSS')"> + +Attack attempt: "click":javascript:alert('XSS') + +Attack attempt: [* image.jpg onload="alert('XSS')" *] +``` + +Texy automatically: +- **Validates HTML** – removes disallowed tags and attributes +- **Filters URLs** – allows only safe schemes (`http:`, `https:`, `mailto:`, `ftp:`) +- **Escapes content** – properly escapes text in attributes +- **Sanitizes attributes** – removes event handlers (`onclick`, `onerror`, ...) + +```php +$texy = new Texy\Texy; +Texy\Configurator::safeMode($texy); + +$input = '<script>alert("XSS")</script>'; +$output = $texy->process($input); + +// Output: empty (script tag removed) +``` + + +URL Validation +-------------- + +Texy checks URLs in all links and images: + +```php +$texy = new Texy\Texy; + +// Set allowed schemes (default in safeMode) +$texy->urlSchemeFilters[Texy\Texy::FILTER_ANCHOR] = + '#https?:|ftp:|mailto:#Ai'; +$texy->urlSchemeFilters[Texy\Texy::FILTER_IMAGE] = + '#https?:#Ai'; +``` + +**Examples of blocked URLs:** + +```texy +"attack":javascript:alert('XSS') // blocked +"attack":data:text/html,<script> // blocked +[* javascript:alert() *] // blocked +``` + + +Filtering HTML Tags +------------------- + +Control via `$allowedTags`: + +```php +$texy = new Texy\Texy; + +// Allow only safe tags +$texy->allowedTags = [ + 'p' => [], + 'strong' => [], + 'em' => [], + 'a' => ['href', 'title'], // only these attributes +]; + +$input = '<p>Text <script>alert()</script></p>'; +$output = $texy->process($input); + +// Output: <p>Text alert()</p> +// (script tag removed) +``` + + +Practical Example +----------------- + +```php +function processComment(string $userInput): string +{ + $texy = new Texy\Texy; + + // Safe mode + Texy\Configurator::safeMode($texy); + + // Additional restrictions + $texy->allowed['link/url'] = false; // disable auto-links + $texy->allowed['html/tag'] = false; // disable HTML + + // Process + return $texy->process($userInput); +} + +// Usage +$comment = $_POST['comment']; +$html = processComment($comment); +echo $html; // safe output +``` + + +Best Practices +-------------- + +1. **Always use safeMode()** for user content +2. **Validate input** before passing to Texy (length, format) +3. **Limit HTML tags** as needed +4. **Check output** – even though Texy is safe, double-checking never hurts +5. **Log suspicious attempts** – can help you identify attackers + +```php +$texy = new Texy\Texy; +Texy\Configurator::safeMode($texy); + +// Logging +$texy->addHandler('htmlTag', function($invocation, $el, $isStart) { + if ($el->getName() === 'script') { + error_log('XSS attempt detected!'); + } + return $invocation->proceed(); +}); +``` diff --git a/texy/en/custom-handlers.texy b/texy/en/custom-handlers.texy new file mode 100644 index 0000000000..c5e49dcf8b --- /dev/null +++ b/texy/en/custom-handlers.texy @@ -0,0 +1,850 @@ +Modifying Element Behavior +************************** + +.[perex] +This chapter describes how you can change the behavior of **existing elements** in Texy - for example, modify how images, links or formatting are processed. If you want to add **completely new syntax** that Texy doesn't know by default, read the chapter [Adding Custom Syntax |custom-syntax]. + +Imagine you want the standard image syntax `[* URL *]` to recognize a special address `[* youtube:dQw4w9WgXcQ *]` and create an embedded player instead of a regular image. + +Or you want to colorize source code listings using a syntax highlighter. And so on. This is exactly what **element handlers** are for - functions that Texy calls when processing specific elements. For example, you register a handler for the `image` element that checks the URL, and if it starts with `youtube:`, returns an iframe instead of a standard image. You don't change the syntax, you just modify what happens with the found construct. + + +Elements and Their Handlers +=========================== + +In Texy terminology, an **element** is the name for a type of item that can be processed in a document. For example, `image` is an element for images, `linkURL` for links, see [default elements |#Default Elements]. Each element has its **default handler**, which is implemented in the corresponding module and handles standard processing. + +When you write `[* image.jpg *]` in text, the parser finds this syntax, creates a `Texy\Image` object with data about the image and calls all handlers registered for the `image` element. If there is no custom handler, only the default handler from `ImageModule` is called, which creates an HTML `<img>` tag. + +You register a handler by calling the `addHandler()` method: + +```php +$texy->addHandler('image', function( + Texy\HandlerInvocation $invocation, + Texy\Image $image, + ?Texy\Link $link, +) { + // your logic here +}); +``` + +The first parameter is the element name, the second is a callback function. The callback always receives a `Texy\HandlerInvocation` object as the first parameter, followed by parameters specific to the given element. + +.[note] +A detailed explanation of all handler types can be found in the chapter [Architecture and Principles |architecture]. + + +How Processing Works +==================== + +When Texy needs to process an element, it creates a `HandlerInvocation` object containing all registered handlers for this type of element. **Your handler is called first** and can: + +- **Delegate** to the next handler by calling `$invocation->proceed()` +- **Modify input** by calling `proceed()` with modified parameters +- **Modify output** by processing the result from `proceed()` +- **Break the chain** by returning its own result without calling `proceed()` + +The `proceed()` method moves processing to the next handler in the chain. If there are no more custom handlers, the default implementation from the module is called. This means your handler has absolute control - it can decide whether the default logic is called at all. + +This mechanism is called **chain of responsibility**: + +```php +$texy->addHandler('image', function( + Texy\HandlerInvocation $invocation, + Texy\Image $image, + ?Texy\Link $link, +) { + // 1. Modify input data before processing + $image->modifier->title = 'Modified title'; + + // 2. Call next handler or default processing + $element = $invocation->proceed($image, $link); + + // 3. Modify resulting HTML element + $element->attrs['loading'] = 'lazy'; + + return $element; +}); +``` + +The execution order is from **last registered to first**. If a module registers its default handler during construction and you then register a custom handler, your handler is called first. This allows you to override or wrap the default behavior. + + +Default Elements +================ + +Texy provides several predefined elements for which you can register custom handlers. Here is their complete list with parameters that the handler receives. + + +image +----- + +Processes images. + +```php +function( + Texy\HandlerInvocation $invocation, + Texy\Image $image, + ?Texy\Link $link, +): Texy\HtmlElement|string|null +``` + +The `$image` parameter contains URL, dimensions and modifiers. The `$link` parameter is provided if the image is a link (syntax `[* img *]:url`). + + +linkReference +------------- + +Processes reference links of type `[ref]`. + +```php +function( + Texy\HandlerInvocation $invocation, + Texy\Link $link, + string $content, +): Texy\HtmlElement|string|null +``` + +The `$link` parameter contains the URL and modifiers loaded from the reference definition. The `$content` parameter is the HTML content of the link (already processed by parsing inline syntax). + + +linkEmail +--------- + +Processes automatically recognized email addresses in text. + +```php +function( + Texy\HandlerInvocation $invocation, + Texy\Link $link, +): Texy\HtmlElement|string|null +``` + +The `$link` parameter contains the email address in the `URL` property. + + +linkURL +------- + +Processes automatically recognized URLs in text. + +```php +function( + Texy\HandlerInvocation $invocation, + Texy\Link $link, +): Texy\HtmlElement|string|null +``` + +The `$link` parameter contains the found URL. + + +phrase +------ + +Processes inline formatting. + +```php +function( + Texy\HandlerInvocation $invocation, + string $phrase, + string $content, + Texy\Modifier $modifier, + ?Texy\Link $link, +): Texy\HtmlElement|string|null +``` + +The `$phrase` parameter is the syntax name like `phrase/strong` or `phrase/em`. The `$content` parameter is the text inside the formatting. The `$modifier` parameter contains CSS classes, styles and other modifiers. The `$link` parameter is provided if the formatting has an attached link. + + +newReference +------------ + +Called when the parser finds a reference that is not defined. + +```php +function( + Texy\HandlerInvocation $invocation, + string $name, +): Texy\HtmlElement|string|null +``` + +The `$name` parameter is the reference name. The handler can create a link dynamically or return `null` to reject. + + +htmlComment +----------- + +Processes HTML comments. + +```php +function( + Texy\HandlerInvocation $invocation, + string $content, +): string +``` + +The `$content` parameter is the text between `<!--` and `-->`. + + +htmlTag +------- + +Processes HTML tags in text. + +```php +function( + Texy\HandlerInvocation $invocation, + Texy\HtmlElement $el, + bool $isStart, + ?bool $forceEmpty, +): Texy\HtmlElement|string|null +``` + +The `$el` parameter is an element with name and attributes. The `$isStart` parameter determines whether it is an opening tag. The `$forceEmpty` parameter forces an empty element. + + +script +------ + +Processes scripts `{{command: args}}`. + +```php +function( + Texy\HandlerInvocation $invocation, + string $command, + array $args, + ?string $raw, +): Texy\HtmlElement|string|null +``` + +The `$command` parameter is the command name. The `$args` parameter is an array of arguments. The `$raw` parameter is the original unparsed argument string. + + +figure +------ + +Processes images with captions. + +```php +function( + Texy\HandlerInvocation $invocation, + Texy\Image $image, + ?Texy\Link $link, + string $content, + Texy\Modifier $modifier, +): Texy\HtmlElement|null +``` + +The `$content` parameter is the caption text below the image. + + +heading +------- + +Processes headings. + +```php +function( + Texy\HandlerInvocation $invocation, + int $level, + string $content, + Texy\Modifier $modifier, + bool $isSurrounded, +): Texy\HtmlElement +``` + +The `$level` parameter is the heading level (0-6). The `$content` parameter is the heading text. The `$isSurrounded` parameter determines whether it is a delimited heading (`###`) or underlined. + + +horizline +--------- + +Processes horizontal lines. + +```php +function( + Texy\HandlerInvocation $invocation, + string $type, + Texy\Modifier $modifier, +): Texy\HtmlElement +``` + +The `$type` parameter is the string of characters used for the line (`---` or `***`). + + +block +----- + +Processes special blocks `/--type` to `\--`. + +```php +function( + Texy\HandlerInvocation $invocation, + string $blocktype, + string $content, + ?string $param, + Texy\Modifier $modifier, +): Texy\HtmlElement|string +``` + +The `$blocktype` parameter is the block type with the `block/` prefix, e.g. `block/code` or `block/html`. The `$content` parameter is the block content. The `$param` parameter is an optional parameter after the type (e.g. language for code). + + +emoticon +-------- + +Processes emoticons (smileys). + +```php +function( + Texy\HandlerInvocation $invocation, + string $emoticon, + string $raw, +): Texy\HtmlElement|string +``` + +The `$emoticon` parameter is the recognized emoticon (e.g. `:-)` or `:-(` ). The `$raw` parameter is the original text including any repeating characters (e.g. `:-)))))` ). + +.[note] +Emoticons are **disabled** by default. You can enable them using `$texy->allowed['emoticon'] = true;` + + +Default Events +============== + +Texy provides several predefined events for which you can register handlers. These are called **notification handlers**. Unlike element handlers, these handlers **don't return anything**. They are used for side effects such as logging, collecting statistics, or modifying the already created DOM tree. + + +beforeParse +----------- + +Called before text parsing begins. Allows you to perform preprocessing or load definitions. + +```php +function( + Texy\Texy $texy, + string &$text, + bool $isSingleLine, +): void +``` + +The `$text` parameter is passed by reference, so you can modify it. The `$isSingleLine` parameter determines whether a single line or the entire document is being parsed. + + +afterParse +---------- + +Called after parsing is complete, before converting the DOM tree to HTML. Allows you to modify the created DOM. + +```php +function( + Texy\Texy $texy, + Texy\HtmlElement $DOM, + bool $isSingleLine, +): void +``` + +The `$DOM` parameter is the root element of the document, which you can traverse and modify. + + +afterList +--------- + +Called after a list (numbered or unnumbered) is created. + +```php +function( + Texy\BlockParser $parser, + Texy\HtmlElement $element, + Texy\Modifier $modifier, +): void +``` + +The `$element` parameter is the created `<ul>` or `<ol>` element. The `$modifier` parameter contains modifiers applied to the entire list. + + +afterDefinitionList +------------------- + +Called after a definition list is created. + +```php +function( + Texy\BlockParser $parser, + Texy\HtmlElement $element, + Texy\Modifier $modifier, +): void +``` + +The `$element` parameter is the created `<dl>` element. + + +afterTable +---------- + +Called after a table is created. + +```php +function( + Texy\BlockParser $parser, + Texy\HtmlElement $element, + Texy\Modifier $modifier, +): void +``` + +The `$element` parameter is the created `<table>` element. + + +afterBlockquote +--------------- + +Called after a blockquote is created. + +```php +function( + Texy\BlockParser $parser, + Texy\HtmlElement $element, + Texy\Modifier $modifier, +): void +``` + +The `$element` parameter is the created `<blockquote>` element. + + +Basic Usage +=========== + +The simplest element handler just delegates to the default processing: + +```php +$texy->addHandler('image', function( + Texy\HandlerInvocation $invocation, + Texy\Image $image, + ?Texy\Link $link, +) { + return $invocation->proceed(); +}); +``` + +This handler doesn't change anything, but shows the basic skeleton. It passes all parameters forward and returns the result. + + +Modifying Input Data +-------------------- + +A handler can modify data before processing: + +```php +$texy->addHandler('image', function( + Texy\HandlerInvocation $invocation, + Texy\Image $image, + ?Texy\Link $link, +) { + // add default dimensions if not specified + $image->width ??= 800; + $image->height ??= 600; + return $invocation->proceed(); +}); +``` + +Changes made to `$image` or `$link` objects will be reflected in further processing, including the default handler. + + +Modifying Output Element +------------------------ + +A handler can modify the HTML element returned from `proceed()`: + +```php +$texy->addHandler('image', function( + Texy\HandlerInvocation $invocation, + Texy\Image $image, + ?Texy\Link $link, +) { + $element = $invocation->proceed(); + + if ($element) { + // add lazy loading + $element->attrs['loading'] = 'lazy'; + + // add CSS class + $element->attrs['class'][] = 'responsive'; + } + + return $element; +}); +``` + + +Conditional Processing +---------------------- + +A handler can process only certain cases and delegate others: + +```php +$texy->addHandler('image', function( + Texy\HandlerInvocation $invocation, + Texy\Image $image, + ?Texy\Link $link, +) { + // special processing for YouTube videos + if (str_starts_with($image->URL, 'youtube:')) { + $id = substr($image->URL, 8); + $iframe = sprintf( + '<iframe src="https://youtube.com/embed/%s"></iframe>', + htmlspecialchars($id) + ); + return $invocation->getTexy() + ->protect($iframe, Texy\Texy::CONTENT_BLOCK); + } + + // process other images normally + return $invocation->proceed(); +}); +``` + + +Interrupting Processing +----------------------- + +A handler can refuse processing by returning `null`: + +```php +$texy->addHandler('image', function( + Texy\HandlerInvocation $invocation, + Texy\Image $image, + ?Texy\Link $link, +) { + // disallow external images + if (str_contains($image->URL, '://')) { + return null; + } + + return $invocation->proceed(); +}); +``` + + +Practical Examples +================== + +The following examples show real use cases for element handlers. + + +YouTube Embed +------------- + +Converting special syntax to embedded video: + +```php +$texy->addHandler('image', function( + Texy\HandlerInvocation $invocation, + Texy\Image $image, + ?Texy\Link $link, +) { + if (str_starts_with($image->URL, 'youtube:')) { + $id = substr($image->URL, 8); + $width = $image->width ?: 560; + $height = $image->height ?: 315; + + $iframe = sprintf( + '<iframe width="%d" height="%d" ' + . 'src="https://youtube.com/embed/%s" ' + . 'frameborder="0" allowfullscreen></iframe>', + $width, $height, htmlspecialchars($id) + ); + + $texy = $invocation->getTexy(); + return $texy->protect($iframe, $texy::CONTENT_BLOCK); + } + + return $invocation->proceed(); +}); +``` + +Usage in text: + +```texy +[* youtube:dQw4w9WgXcQ 640x360 *] +``` + + +Image Gallery +------------- + +Wrapping images in a special div for lightbox: + +```php +$texy->addHandler('image', function( + Texy\HandlerInvocation $invocation, + Texy\Image $image, + ?Texy\Link $link, +) { + $element = $invocation->proceed(); + + // if image has 'gallery' class + if (isset($image->modifier->classes['gallery'])) { + // wrap in div with lightbox attributes + $wrapper = new Texy\HtmlElement('div'); + $wrapper->attrs['class'][] = 'lightbox-item'; + $wrapper->attrs['data-src'] = $image->URL; + $wrapper->add($element); + + return $wrapper; + } + + return $element; +}); +``` + +Usage: + +```texy +[* image.jpg .[gallery] *] +``` + + +Link Validation +--------------- + +Checking whether links found in text lead to allowed domains: + +```php +$allowedDomains = ['example.com', 'trusted.org']; + +$texy->addHandler('linkURL', function( + Texy\HandlerInvocation $invocation, + Texy\Link $link, +) use ($allowedDomains) { + $host = parse_url($link->URL, PHP_URL_HOST); + + // if domain is not in whitelist, disallow link + if ($host && !in_array($host, $allowedDomains, true)) { + return null; + } + + return $invocation->proceed(); +}); +``` + + +Automatic rel="nofollow" +------------------------ + +Adding `nofollow` to all external links found in text: + +```php +$texy->addHandler('linkURL', function( + Texy\HandlerInvocation $invocation, + Texy\Link $link, +) { + $element = $invocation->proceed(); + + // if link contains :// (i.e. is external) + if (str_contains($link->URL, '://')) { + $element->attrs['rel'] = 'nofollow'; + } + + return $element; +}); +``` + + +Syntax Highlighting +------------------- + +Integrating a syntax highlighting library: + +```php +$texy->addHandler('block', function( + Texy\HandlerInvocation $invocation, + string $blocktype, + string $content, + ?string $param, + Texy\Modifier $modifier, +) { + // process only 'code' type blocks + if ($blocktype !== 'block/code') { + return $invocation->proceed(); + } + + // apply syntax highlighting + $highlighter = new MyHighlighter(); + $highlighted = $highlighter->highlight($content, $param); + + $el = new Texy\HtmlElement('pre'); + $modifier->decorate($invocation->getTexy(), $el); + $el->attrs['class'][] = 'language-' . $param; + + $code = new Texy\HtmlElement('code'); + $code->add($highlighted); + $el->add($code); + + return $el; +}); +``` + + +Lazy Loading +------------ + +Iterating through all images and adding lazy loading: + +```php +$texy->addHandler('afterParse', function( + Texy\Texy $texy, + Texy\HtmlElement $DOM, + bool $isSingleLine, +) { + foreach ($DOM->getIterator() as $child) { + if ($child instanceof Texy\HtmlElement + && $child->getName() === 'img' + ) { + $child->attrs['loading'] = 'lazy'; + } + } +}); +``` + + +Logging Used Elements +--------------------- + +Collecting statistics about used elements in the document: + +```php +$stats = []; + +$texy->addHandler('beforeParse', function( + Texy\Texy $texy, + string &$text, + bool $isSingleLine, +) use (&$stats) { + $stats = ['images' => 0, 'links' => 0, 'headings' => 0]; +}); + +$texy->addHandler('image', function( + Texy\HandlerInvocation $invocation, + Texy\Image $image, + ?Texy\Link $link, +) use (&$stats) { + $stats['images']++; + return $invocation->proceed(); +}); + +$texy->addHandler('linkURL', function( + Texy\HandlerInvocation $invocation, + Texy\Link $link, +) use (&$stats) { + $stats['links']++; + return $invocation->proceed(); +}); + +$texy->addHandler('heading', function( + Texy\HandlerInvocation $invocation, + int $level, + string $content, + Texy\Modifier $modifier, + bool $isSurrounded, +) use (&$stats) { + $stats['headings']++; + return $invocation->proceed(); +}); +``` + + +Helper Classes +============== + +When working with handlers, you will work with several important classes. Here is an overview with their most important properties. + + +Texy\Image +---------- + +Represents an image with its parameters: + +```php +$image->URL; // string - path to image +$image->linkedURL; // ?string - link URL (if image is a link) +$image->width; // ?int - width in pixels +$image->height; // ?int - height in pixels +$image->asMax; // bool - whether dimensions are maximum +$image->modifier; // Modifier - CSS classes, styles, attributes +$image->name; // ?string - reference name +``` + + +Texy\Link +--------- + +Represents a link with its parameters: + +```php +$link->URL; // string - target URL +$link->raw; // string - original URL (before normalization) +$link->modifier; // Modifier - CSS classes, styles, attributes +$link->type; // string - link type (COMMON, BRACKET, IMAGE) +$link->label; // ?string - link text (for references) +$link->name; // ?string - reference name +``` + +Constants for link type: + +```php +Texy\Link::COMMON; // common link +Texy\Link::BRACKET; // reference link [ref] +Texy\Link::IMAGE; // link from image [* img *] +``` + + +Texy\HtmlElement +---------------- + +Represents an HTML element with its attributes and content: + +```php +$el = new Texy\HtmlElement('div'); + +// working with element name +$el->getName(); // returns 'div' +$el->setName('section'); // changes to 'section' + +// working with attributes +$el->attrs['id'] = 'main'; +$el->attrs['class'][] = 'container'; +$el->attrs['style']['color'] = 'red'; + +// working with content +$el->setText('text'); // sets text content +$el->getText(); // returns text content +$el->add($child); // adds child +$el->insert(0, $child); // inserts child at position + +// parsing content +$el->parseLine($texy, $text); // parses inline text +$el->parseBlock($texy, $text); // parses block text + +// conversion to HTML +$el->toString($texy); // internal representation +$el->toHtml($texy); // final HTML +``` + + +Texy\Modifier +------------- + +Represents modifiers for CSS classes, styles and attributes: + +```php +$mod->id; // ?string - HTML id +$mod->classes; // array - array of CSS classes +$mod->styles; // array - array of CSS styles +$mod->attrs; // array - HTML attributes +$mod->hAlign; // ?string - horizontal alignment (left, right, center, justify) +$mod->vAlign; // ?string - vertical alignment (top, middle, bottom) +$mod->title; // ?string - title attribute or alt for images + +// applying modifier to element +$mod->decorate($texy, $element); +``` diff --git a/texy/en/custom-syntax.texy b/texy/en/custom-syntax.texy new file mode 100644 index 0000000000..9a8365fc43 --- /dev/null +++ b/texy/en/custom-syntax.texy @@ -0,0 +1,519 @@ +Adding Custom Syntax +******************** + +.[perex] +This chapter describes how to add **completely new markup constructs** to Texy that don't exist by default. If you only want to modify the behavior of existing elements (for example, adjust image or link processing), read the chapter [Custom Element Behavior |custom-handlers]. + +Imagine you want to automatically create links to user profiles in documentation by writing `@@username`. Or you need special alert blocks like `:::warning`. Texy doesn't recognize these constructs, and you can't create them by modifying existing elements. + +Custom syntax allows you to define new markup constructs. You specify what the construct should look like (using a regular expression) and write a function to process it. Texy will then recognize your syntax just like its standard constructs. + + +Syntax Registration +=================== + +Texy provides two methods for registering custom syntax, depending on whether it's an inline or block element. + + +Line Syntax +----------- + +Line syntax is used for inline constructs within text lines. You register it using the `registerLinePattern()` method: + +```php +$texy->registerLinePattern( + callable $handler, + string $pattern, + string $name, + ?string $againTest = null, +); +``` + +**The `$handler` parameter** is a callback function that gets called when the syntax is found. It can be a function name, anonymous function, or array `[$object, 'method']`. + +**The `$pattern` parameter** is a regular expression (PCRE) that defines what your syntax looks like in the text. The pattern **should not be anchored** to the start of a line (`^`), since it's searched for anywhere in the text. Use capturing groups to capture the data you need to process. + +**The `$name` parameter** is a unique syntax name. It's used in the `$texy->allowed` array for enabling/disabling and passed to the handler for identification. We recommend using a prefix style like `custom/username` or `myapp/profile`. + +**The `$againTest` parameter** is an optional regex for optimization. If specified, Texy first checks whether the text contains anything that could match your pattern. Only if `$againTest` succeeds does it run the more complex pattern. This significantly speeds up processing if you have a complex pattern that's rarely used. + +Registration example: + +```php +$texy->registerLinePattern( + 'usernameHandler', + '#@@([a-z0-9_]+)#i', + 'custom/username', +); +``` + + +Block Syntax +------------ + +Block syntax is used for multi-line block constructs. You register it using the `registerBlockPattern()` method: + +```php +$texy->registerBlockPattern( + callable $handler, + string $pattern, + string $name, +); +``` + +The `$handler` and `$name` parameters have the same meaning as for line syntax. + +**The `$pattern` parameter** is a regular expression that **must be anchored** to the start of a line (`^`) and often to the end (`$`) as well. BlockParser automatically adds the `Am` modifiers (anchored, multiline), so don't add them to the pattern. The pattern should match the entire block or at least its beginning. + +Registration example: + +```php +$texy->registerBlockPattern( + 'alertHandler', + '#^:::(warning|info|danger)\n(.+)$#s', + 'custom/alert', +); +``` + + +Syntax Handler +============== + +A syntax handler is a function called by the parser when it finds an occurrence of your syntax in the text. Its job is to process the found data and return an HTML element or string. + +A detailed explanation of the syntax handler's role in Texy's architecture can be found in the chapter [Architecture and Principles |architecture#syntax-handler]. + + +For Line Syntax +--------------- + +Syntax handler signature for line syntax: + +```php +function( + Texy\LineParser $parser, + array $matches, + string $name, +): Texy\HtmlElement|string|null +``` + +**The `$parser` parameter** provides access to the parser and Texy object. You'll most often use `$parser->getTexy()` to get the Texy instance. + +**The `$matches` parameter** contains the regex match results. `$matches[0]` is the entire matched string, `$matches[1]`, `$matches[2]` etc. are the capturing groups from your pattern. + +**The `$name` parameter** is the syntax name you specified during registration. Useful if one handler processes multiple syntaxes. + +**The return value** can be `Texy\HtmlElement` for structured HTML output, `string` for direct HTML code (which you must protect), or `null` to refuse processing. + +The handler can set `$parser->again = true` if it wants the content of the created element to be parsed again to find nested syntaxes. + + +For Block Syntax +---------------- + +Syntax handler signature for block syntax: + +```php +function( + Texy\BlockParser $parser, + array $matches, + string $name, +): Texy\HtmlElement|string|null +``` + +The parameters have the same meaning as for line syntax, except you receive `Texy\BlockParser` instead of `LineParser`. + +BlockParser provides methods for working with multi-line structures: + +- **`$parser->next($pattern, &$matches)`** - matches the next line against the pattern and returns true/false +- **`$parser->moveBackward($lines)`** - moves back the specified number of lines +- **`$parser->isIndented()`** - returns true if the current block is indented + + +LineParser API +============== + +When working with line syntax, you have several useful properties and methods available. + +**The `$again` property** controls whether the currently processed syntax should be searched for again at the same position after processing. The default value is `false`. Set to `true` if you're creating an element with content that may contain other syntaxes: + +```php +function( + Texy\LineParser $parser, + array $matches, + string $name, +): Texy\HtmlElement +{ + $el = new Texy\HtmlElement('span'); + $el->setText($matches[1]); + + // content may contain additional formatting + $parser->again = true; + + return $el; +} +``` + +**The `getTexy()` method** returns the Texy object instance, which you need for working with `protect()` or accessing configuration. + + +BlockParser API +=============== + +When working with block syntax, you have methods available for working with multi-line structures. + +**The `next($pattern, &$matches)` method** tries to match the next line in the text against the specified pattern. If successful, it fills `$matches` with the result and moves the internal position past this line. Returns `true` on success, `false` on failure: + +```php +while ($parser->next('#^\-\s+(.+)$#', $matches)) { + // process next list item + $item = $matches[1]; +} +``` + +**The `moveBackward($lines = 1)` method** moves the internal position back the specified number of lines. Useful when your pattern matched more than the block's start and you want to return to the beginning: + +```php +// pattern matched 3 lines, but we want to read from the first +$parser->moveBackward(2); +``` + +**The `isIndented()` method** returns `true` if the current block is indented (starts with a space or tab). This indicates that it's nested content. + + +Practical Examples +================== + +The following examples demonstrate real use cases for custom syntax. + + +User Profiles +------------- + +Automatic creation of profile links by writing `@@username`: + +```php +$texy->registerLinePattern( + function( + Texy\LineParser $parser, + array $matches, + string $name, + ): Texy\HtmlElement + { + $username = $matches[1]; + + $el = new Texy\HtmlElement('a'); + $el->attrs['href'] = '/user/' . urlencode($username); + $el->attrs['class'][] = 'user-profile'; + $el->setText('@' . $username); + + return $el; + }, + '#@@([a-z0-9_]+)#i', + 'custom/username' +); +``` + +Usage in text: + +```texy +Check out the profile of @@johndoe or @@jane_smith. +``` + + +Alert Boxes +----------- + +Special alert blocks with different types: + +```php +$texy->registerBlockPattern( + function( + Texy\BlockParser $parser, + array $matches, + string $name, + ): Texy\HtmlElement + { + $type = $matches[1]; // warning, info, danger + $content = $matches[2]; + + $el = new Texy\HtmlElement('div'); + $el->attrs['class'][] = 'alert'; + $el->attrs['class'][] = 'alert-' . $type; + + $texy = $parser->getTexy(); + $el->parseBlock($texy, trim($content)); + + return $el; + }, + '#^:::(warning|info|danger)\n(.+?)(?=\n:::|$)#s', + 'custom/alert' +); +``` + +Usage in text: + +```texy +:::warning +This is an important warning! +::: + +:::info +For your information: the update will take place tomorrow. +::: +``` + + +Hashtags +-------- + +Automatic creation of links from hashtags: + +```php +$texy->registerLinePattern( + function( + Texy\LineParser $parser, + array $matches, + string $name, + ): Texy\HtmlElement + { + $tag = $matches[1]; + + $el = new Texy\HtmlElement('a'); + $el->attrs['href'] = '/tag/' . urlencode($tag); + $el->attrs['class'][] = 'hashtag'; + $el->setText('#' . $tag); + + return $el; + }, + '#\#([a-z0-9_]+)#i', + 'custom/hashtag', + '#\##' // optimization - search only if # is in text +); +``` + +Usage: + +```texy +Article about #php and #webdesign. +``` + + +Abbreviations +------------- + +Automatic expansion of abbreviations with explanation: + +```php +$abbreviations = [ + 'HTML' => 'HyperText Markup Language', + 'CSS' => 'Cascading Style Sheets', + 'PHP' => 'PHP: Hypertext Preprocessor', +]; + +$texy->registerLinePattern( + function( + Texy\LineParser $parser, + array $matches, + string $name + ) use ($abbreviations): ?Texy\HtmlElement + { + $abbr = $matches[1]; + + if (!isset($abbreviations[$abbr])) { + return null; // unknown abbreviation + } + + $el = new Texy\HtmlElement('abbr'); + $el->attrs['title'] = $abbreviations[$abbr]; + $el->setText($abbr); + + return $el; + }, + '#\b([A-Z]{2,})\b#', + 'custom/abbreviation' +); +``` + + +Inline Icons +------------ + +Inserting icons using special syntax: + +```php +$texy->registerLinePattern( + function( + Texy\LineParser $parser, + array $matches, + string $name, + ): Texy\HtmlElement + { + $icon = $matches[1]; + + $el = new Texy\HtmlElement('i'); + $el->attrs['class'][] = 'icon'; + $el->attrs['class'][] = 'icon-' . $icon; + $el->attrs['aria-hidden'] = 'true'; + + return $el; + }, + '#:icon-([a-z-]+):#', + 'custom/icon' +); +``` + +Usage: + +```texy +Click the button :icon-download: to download. +``` + + +Note Block +---------- + +Block for footnotes: + +```php +$texy->registerBlockPattern( + function( + Texy\BlockParser $parser, + array $matches, + string $name + ): Texy\HtmlElement + { + $parser->moveBackward(); + + $content = ''; + while ($parser->next('#^NOTE:\s*(.+)$#', $matches)) { + $content .= $matches[1] . "\n"; + } + + $el = new Texy\HtmlElement('aside'); + $el->attrs['class'][] = 'note'; + + $texy = $parser->getTexy(); + $el->parseBlock($texy, trim($content)); + + return $el; + }, + '#^NOTE:\s*(.+)$#m', + 'custom/note' +); +``` + +Usage: + +```texy +NOTE: This is an important note. +NOTE: It can be multi-line. +``` + + +Custom Quotations with Author +----------------------------- + +Extended syntax for quotations with author attribution: + +```php +$texy->registerBlockPattern( + function( + Texy\BlockParser $parser, + array $matches, + string $name, + ): Texy\HtmlElement + { + $author = $matches[1]; + $quote = $matches[2]; + + $blockquote = new Texy\HtmlElement('blockquote'); + + $texy = $parser->getTexy(); + $blockquote->parseBlock($texy, trim($quote)); + + $cite = new Texy\HtmlElement('cite'); + $cite->setText($author); + $blockquote->add($cite); + + return $blockquote; + }, + '#^QUOTE\[([^\]]+)\]:\n(.+?)(?=\n\n|$)#s', + 'custom/quote' +); +``` + +Usage: + +```texy +QUOTE[Albert Einstein]: +Imagination is more important than knowledge, +because knowledge is limited. +``` + + +Image Gallery +------------- + +Special block for creating a gallery from multiple images: + +```php +$texy->registerBlockPattern( + function( + Texy\BlockParser $parser, + array $matches, + string $name, + ): Texy\HtmlElement + { + $parser->moveBackward(); + + $gallery = new Texy\HtmlElement('div'); + $gallery->attrs['class'][] = 'gallery'; + + while ($parser->next('#^\[G\]\s*(.+)$#', $matches)) { + $img = new Texy\HtmlElement('img'); + $img->attrs['src'] = trim($matches[1]); + $img->attrs['loading'] = 'lazy'; + $gallery->add($img); + } + + return $gallery; + }, + '#^\[G\]\s*(.+)$#m', + 'custom/gallery' +); +``` + +Usage: + +```texy +[G] image1.jpg +[G] image2.jpg +[G] image3.jpg +``` + + +Syntax Collisions +================= + +When registering custom syntax, you must be careful that it doesn't collide with existing Texy syntaxes or other custom syntaxes. + +**Registration order matters.** Line syntaxes are searched in the order they were registered. If multiple syntaxes can match at the same position, the one registered earlier wins. Therefore, register more specific syntaxes before more general ones. + +**Be specific in patterns.** The more concrete your pattern is, the lower the risk of collision. The pattern `#\#\w+#` also matches `#heading`, which could collide with headings. Better is `#(?<=\s)\#[a-z0-9_]+#i`, which requires a space before the hashtag. + +**Test combinations.** Try how your syntax works in combination with existing constructs. What happens when your markup is inside a link? What if it's inside a code block? + +**Use prefixed names.** Instead of `username`, use `custom/username` or `myapp/username`. This prevents conflicts if Texy adds syntax with the same name in the future. + + +Best Practices +============== + +**Return `null` on failure.** If the handler determines it can't or doesn't want to process the given match (for example, an unknown abbreviation), return `null`. The parser will then try other syntaxes. + +**Use `protect()` for HTML.** If you're returning a raw HTML string instead of `HtmlElement`, you must protect it using `$texy->protect($html, Texy::CONTENT_...)`. Otherwise it will be escaped. + +**Set `$parser->again` correctly.** For line syntaxes that create an element with text content that may contain other syntaxes (formatting, links), set `$parser->again = true`. + +**Respect `$texy->allowed`.** If you're creating a module with multiple syntaxes, check `$texy->allowed[$name]` before registering the pattern or in the handler before processing. diff --git a/texy/en/develop.texy b/texy/en/develop.texy new file mode 100644 index 0000000000..1b3c0eda6c --- /dev/null +++ b/texy/en/develop.texy @@ -0,0 +1,35 @@ +For Developers +************** + +.[perex] +Welcome to the Texy programmer documentation! This section will guide you from basic usage to advanced techniques of extension and custom syntax. + + +[Quick Start | quickstart] +-------------------------- + +Installation, first use and basic configuration. In 5 minutes you will have Texy functional. + + +[Configuration | configuration] +------------------------------- + +Complete overview of all modules, their properties and configuration options. Security settings, allowed tags, styles and classes. + + +[Custom Element Behavior | custom-handlers] +------------------------------------------- + +Learn how to change the behavior of existing syntax. YouTube embedding, syntax highlighting, custom validation. + + +[Adding Custom Syntax | custom-syntax] +-------------------------------------- + +Creating completely new syntactic elements. + + +[Architecture and Principles | architecture] +-------------------------------------------- + +Understanding how Texy works internally. Parsing flow, modules, pattern matching, protect/unprotect mechanism. diff --git a/texy/en/quickstart.texy b/texy/en/quickstart.texy new file mode 100644 index 0000000000..a1214045a6 --- /dev/null +++ b/texy/en/quickstart.texy @@ -0,0 +1,205 @@ +Quick Start +*********** + +.[perex] +Learn how to work with Texy in just a few minutes. This page guides you through installation, first use, and basic configuration. + + +Installation +============ + +Texy leverages modern PHP features and requires at least version 8.1. + +The simplest installation method is via Composer: + +```bash +composer require texy/texy +``` + +Composer will automatically download Texy and all its dependencies. + + +First Use +========= + + +Basic Text Processing +--------------------- + +Creating a Texy instance and processing text is extremely simple: + +```php +require __DIR__ . '/vendor/autoload.php'; + +$texy = new Texy\Texy; + +$text = 'This is **bold text** and this is //italic//.'; +$html = $texy->process($text); + +echo $html; +``` + +Output: +```latte +<p>This is <strong>bold text</strong> and this is <em>italic</em>.</p> +``` + +The `process()` method processes the entire text including block elements (paragraphs, headings, lists, tables...). + + +Single-line Text +---------------- + +If you're processing only single-line text without block elements (such as database headings or short descriptions): + +```php +$texy = new Texy\Texy; + +$text = 'Link to "homepage":https://example.com'; +$html = $texy->processLine($text); + +echo $html; +``` + +Output: +```latte +Link to <a href="https://example.com">homepage</a> +``` + +The `processLine()` method doesn't wrap the output in a `<p>` paragraph and processes only inline elements. + + +Basic Configuration +=================== + +Texy works out of the box, but you'll often want to adjust the basic settings. + + +Setting Image Paths +------------------- + +If you're using relative paths to images, set the root directory: + +```php +$texy = new Texy\Texy; + +// Web path (prepended to relative URLs) +$texy->imageModule->root = '/images/'; + +// Physical disk path (for determining dimensions) +$texy->imageModule->fileRoot = __DIR__ . '/public/images/'; +``` + +Now when you write `[* photo.jpg *]`, Texy will generate `<img src="/images/photo.jpg">` and automatically determine the image dimensions. + + +Setting Link Paths +------------------ + +Similarly, you can set the root directory for links: + +```php +$texy->linkModule->root = '/articles/'; +``` + + +Enabling and Disabling Syntaxes +------------------------------- + +Each part of the Texy syntax can be disabled or enabled using the `$allowed` array: + +```php +$texy = new Texy\Texy; + +// Disable images +$texy->allowed['image'] = false; + +// Disable HTML tags in input +$texy->allowed['html/tag'] = false; + +// Enable emoticons (disabled by default) +$texy->allowed['emoticon'] = true; +``` + +A complete list of syntax options can be found in [configuration | configuration#allowed]. + + +Safe Mode for User Content +-------------------------- + +If you're processing content from users (comments, forum posts), use safe mode: + +```php +$texy = new Texy\Texy; +Texy\Configurator::safeMode($texy); + +$userInput = $_POST['comment']; +$html = $texy->process($userInput); +``` + +SafeMode: +- Allows only **safe HTML tags** (`<strong>`, `<em>`, `<a>`, ...) +- Disables **classes and IDs** +- Disables **inline styles** +- Disables **images** +- Adds `rel="nofollow"` to all links +- Filters **URL schemes** (only `http:`, `https:`, `ftp:`, `mailto:`) + +More about security in the chapter [Configuration – Security |configuration#Security]. + + +Complete Example +================ + +```php +require __DIR__ . '/vendor/autoload.php'; + +$texy = new Texy\Texy; + +// Configuration +$texy->imageModule->root = '/images/'; +$texy->linkModule->root = '/'; +$texy->allowed['html/tag'] = false; + +// Text to process +$text = ' + + +Article Heading +=============== + +This is an **introductory paragraph** with a link to "homepage":https://example.com. + +- First item +- Second item +- Third item + +[* photo.jpg .(Photograph) *] +'; + +// Processing +$html = $texy->process($text); + +// Output +echo $html; + +// Additional information +echo "Page title: " . $texy->headingModule->title; +print_r($texy->summary['links']); +print_r($texy->summary['images']); +``` + +After processing, you have access to: +- `$texy->headingModule->title` – first heading (suitable for `<title>`) +- `$texy->summary['links']` – array of all used links +- `$texy->summary['images']` – array of all used images + + +Next Steps +========== + +Now you know how to use Texy. Continue with: + +- **[Configuration | configuration]** – detailed settings for all modules +- **[Syntax | syntax]** – learn the Texy markup +- **[Architecture | architecture]** – understand how Texy works internally diff --git a/texy/en/syntax.texy b/texy/en/syntax.texy new file mode 100644 index 0000000000..5ad42c4062 --- /dev/null +++ b/texy/en/syntax.texy @@ -0,0 +1,891 @@ +Syntax +****** + +.[perex] +Texy was created to allow inexperienced users to easily edit website content. Therefore, its syntax is intuitive and clear. + + +Cheat Sheet +=========== + +| [Text Formatting |#Text formatting] | Syntax +|----------------------------------------------- +| [Bold text |#Text formatting] | .[text-code] ''**bold text**'' +| [Italics |#Text formatting] | ''*italics*'' or ''//italics//'' +| [Inline code |#Text formatting] | ''`code`'' +| [#Links] | ''"text":URL'' or ''[text](URL)'' +| [#Images] | ''[* image.jpg *]'' +| [#Disabling Formatting] | ''special characters'' +|----------------------------------------------- +| Elements +|----------------------------------------------- +| [#Underlined Headings] | H1 <br> === +| [#Surrounded Headings] | ''### H1'' <br> ## H2 +| [#Bulleted Lists] | ''- first'' <br> ''- second'' +| [#Numbered Lists] | ''1) first'' <br> ''2) second'' +| [#Definition Lists] | term: <br>   ''- first'' +| [#Blockquotes] | ''> blockquote'' +| [#Horizontal Rules] | ''---'' +| [#Tables] | ''\| cell \| cell \|'' +| [Code Blocks |#Preformatted text] | ''/--'' <br> ... <br> ''\--'' +|----------------------------------------------- +| Modifiers .[#toc-modifiers] +|-------------------------------------------------------- +| title | ''.(title)'' +| CSS class | ''.[btn btn-primary]'' +| ID | ''.[#id]'' +| CSS style or HTML attribute | ''.{color: blue}'' or ''.{target: _blank}'' +| horizontal alignment | ''.< .> .<> .='' +| vertical alignment | ''.^ .- ._'' + + +Paragraphs of text +================== + +Texy considers a paragraph to be one or more consecutive lines of text. As soon as you leave **one blank line** between them, Texy automatically understands that it should start a new paragraph. + +This means that Texy will join lines that belong together. You don't have to worry about a sentence breaking in the middle when you shrink the editor window. + +```texy +This is the first paragraph. It can easily have multiple lines, +and Texy will join them into one continuous block of text. + +Only here, after a blank line, does a completely new, second paragraph begin. +``` + +However, line merging can be disabled in the configuration, after which each line is considered a separate paragraph: + +/--php +$texy->mergeLines = false; +\-- + + +Line Breaks +----------- + +But what if you just need to break a line without creating a whole new paragraph? This is typically useful for poems, song lyrics, or when writing an address. **Start the new line with a single space**. + +```texy +Karel Novák, + U Tiché pošty 5 + 150 00 Praha 5 +``` + + +Styling Paragraphs +------------------ + +Sometimes you need to distinguish an entire paragraph—for example, to make it a lead paragraph of an article, center it, or assign it a specific style for a border. This is where [#modifiers] come in, which you can place either on a separate line **before** the paragraph or at the end of its last line. + +```texy +.[perex] +This is the lead paragraph of the article, which, thanks to the modifier, +will get the CSS class "perex" and can thus look different from the rest of the text. + +This paragraph, in turn, has a unique ID assigned. .[#section-intro] + +And this paragraph will be centered. .<> +``` + + +Text formatting +=============== + +| syntax | output | Syntax ID +|----------------------------------------------------------------------------- +| .[text-code] ''**bold text**'' | **bold text** | `phrase/strong` +| ''*italics* or //italics//'' | *italics* | `phrase/em-alt`, `phrase/em` +| ''***bold italics***'' | ***bold italics*** | `phrase/strong+em` +| ''`inline code`'' | `inline code` | `phrase/code` +| ''x^2 … O_2'' | x^2 … O_2 | `phrase/sup-alt`, `phrase/sub-alt` +| ''x^^2^^ … O__2__'' | x^2 … O_2 | `phrase/sup`🔸, `phrase/sup`🔸 +| ''++inserted text++'' | <ins>inserted text</ins> | `phrase/ins`🔸 +| ''--deleted text--'' | <del>deleted text</del> | `phrase/del`🔸 +| ''>>quoted text<<'' | >>quoted text<< | `phrase/quote` +| ''"blue text .{color: blue}"'' | "blue text .{color: blue}" | `phrase/span` +| ''~blue text .{color: blue}~'' | ~blue text .{color: blue}~ | `phrase/span-alt` +| ''"et al."((and others))'' | "et al."((and others)) | `phrase/acronym` +| ''NBA((National Basketball Association))'' | NBA((National Basketball Association)) | `phrase/acronym-alt` + +Syntaxes marked with 🔸 are not enabled by default and you must turn them on. For example: + +/--php +$texy->allowed['phrase/ins'] = true; +\-- + +For simple numerical indices, you can use the shorthand syntax `x^2` and `O_2`, but for more complex cases, the double-character variant is more robust, or you can use the HTML tags `<sup>` and `<sub>`. + +There **must not be spaces** inside the syntax characters: + +```texy +Wrong: ** this will not be bold ** +Correct: **this will be bold** +``` + + +Styling Text +------------ + +This is one of Texy's most powerful features. You can "attach" [#modifiers] to any formatted text to add a CSS class, ID, or direct style. The modifier is always inserted **just before the closing tag**: + +```texy +This text is **strong and green .{color:green}** like the Hulk. + +Warning: --This feature is deprecated .[deprecated]-- +``` + +If you want to apply a modifier to text without making it bold or italic, use quotation marks `"` or tildes `~` as the enclosing characters. Texy will then create a universal HTML `<span>` tag with your styles: + +```texy +Regular text, but "this piece is red .{color: red}", and the rest is not. +``` + + +Formatting and Links in One +--------------------------- + +You can turn formatted text into a link - simply add a colon and the URL: + +```texy +Visit our **new gallery**:https://example.com/gallery +``` + +This works for bold text, italics, and inline code. + + +Writing Special Characters +-------------------------- + +What if you want to write `**text**` literally, including the asterisks, without it becoming bold text? You have three options: + +- a backslash is the quickest way to escape a single special character `\**text\**` +- double apostrophes [disable Texy|#Disabling Formatting] for the entire phrase `''**text**''` +- you can use standard HTML entities `**text**` + + +Links +===== + +Links are the soul of the internet. In Texy, their creation is designed to be as natural and clear as possible directly within the text. + +The basic syntax for a link is simple and highly readable. Enclose the linked text in `"` (or other characters for [#text formatting]) and immediately append a colon and the target URL: + +```texy +Visit the official website of the "Nette Framework":https://nette.org. + +If you have a question, "email us":info@example.com. +``` + +The advantage is that Texy is intelligent and automatically recognizes where the URL ends. So you don't have to worry about it accidentally including a period or comma at the end of a sentence in the link. However, if the URL contains non-standard characters, you can enclose it in square brackets to precisely define the start and end of the address: + +```texy +"Read our article":[https://example.com/news?id=1&category=articles] +``` + +Syntax ID `phrase/span`, `phrase/span-alt` | [PhraseModule |configuration#phrasemodule] and [LinkModule |configuration#linkmodule] + + +Alternative Link Syntax +----------------------- + +Are you used to the format used by Markdown or Wikipedia? Texy understands them too. You can choose the style that suits you best. + +```texy +[Link text](https://address.com) // Style known from Markdown +[Link text | https://address.com] // Style known from MediaWiki +text:[target URL or reference] // Single-word link +``` + +Syntax ID `phrase/markdown`, `phrase/wikilink`, `phrase/quicklink` | [PhraseModule |configuration#phrasemodule] + + +Organizing Links with References +-------------------------------- + +When writing longer texts, it can be inconvenient to insert long URLs directly into paragraphs—it can harm readability and clarity. For these cases, Texy has **reference links**. + +In the text, you use only a short, easily memorable reference name. And at the end of the document, you define all these references clearly. + +```texy +We recommend studying the "official documentation":[doc] and going through the "syntax examples":[syntax]. +The entire project is built on [Nette]. + +​[doc]: https://texy.nette.org/en/ "Texy Documentation!" +​[syntax]: https://texy.nette.org/en/syntax +​[Nette]: https://nette.org +``` + +Syntax ID `link/reference`, `link/definition` | [LinkModule |configuration#linkmodule] + + +Automatic Links +--------------- + +Whenever you write a URL (starting with `http://`, `https://`, `www.`) or an email address in the text, Texy will automatically recognize it and convert it into a clickable link. You don't have to do anything at all. + +```texy +You can find our website at www.example.com. +For support, write to support@example.com. +``` + +Syntax ID `link/url`, `link/email` | [LinkModule |configuration#linkmodule] + + +Styling Links +------------- + +With [#modifiers], you can easily add other properties to links: + +```texy +"External link .[external](Opens in a new window){target:_blank}":https://google.com +``` + +The special class `nofollow` adds the `rel="nofollow"` attribute to the link, signaling to search engines not to follow this link. This is useful, for example, for links in comments. + +```texy +"A link I don't trust .[nofollow]":https://example.com +``` + + +Automatic Email Masking +----------------------- + +Texy automatically obfuscates (masks) email addresses from spambots: + +```latte +<a href="mailto:info@example.com">info@<!-- -->example.com</a> +``` + +You can disable this behavior: + +/--php +$texy->obfuscateEmail = false; +\-- + + +Direct HTML +=========== + +Texy is designed so that you don't have to write HTML at all. But what if you encounter a situation where inserting a direct HTML tag is simpler, or you need to create something that Texy's syntax doesn't cover? No problem. Texy gives you complete freedom to combine both worlds. + +You can seamlessly switch between Texy syntax and pure HTML whenever it suits you. + +```texy +This is **bold text** in Texy and this is <strong>bold text</strong> using HTML. + +<div class="info-box"> + <h3>You can also insert entire complex blocks</h3> +</div> +``` + +You might think that inserting direct HTML can be risky. What if you make a mistake or someone inserts malicious code? Texy thinks about this and acts as an intelligent filter and helper: + +- **Corrects errors:** Texy ensures that the resulting code is always valid and won't break your page. +- **Monitors security:** By default, Texy has a list of allowed tags and their attributes. If an unknown tag or a potentially dangerous attribute (e.g., `onclick`) appears in the code, Texy will safely remove it. This protects your website from XSS attacks. +- **Ensures a consistent output:** No matter what HTML code you insert, Texy will make sure the result is always well-formed. + +You can customize this protective shield. Using the `$texy->allowedTags` configuration, you can precisely define which HTML tags and attributes are allowed on your website and which are not. + +This gives you full control over what HTML, for example, editors can use, ensuring the consistency and security of the entire site. For more information, see the "configuration":configuration#allowedtags section. + +Syntax ID `html/tag`, `html/comment` | [HtmlModule |configuration#htmlmodule] + + +Headings +======== + +Texy offers you two elegant and intuitive ways to create headings: **underlined** and **surrounded**. + + +Underlined Headings +------------------- + +This style is reminiscent of a typewriter. Simply place an underline (at least 3 characters) below the heading. The importance of the title is determined by the underlining character. From highest to lowest, these are: `#` `*` `=` `-` + +```texy +This is the most important heading of the entire document +​################################################ + +And this is a second-level heading +​****************************** +``` + +Syntax ID `heading/underlined` | [HeadingModule |configuration#headingmodule] + + +Surrounded Headings +------------------- + +This method is very quick to write. You "wrap" the heading text between `#` or `=` characters. Here, the level of the heading is determined by the **number** of characters used (2 to 7). The more characters, the more important the heading. + +```texy +=== Most important heading (H1) + +== Less important (H2) + +# Even less important (H3) +``` + +You can use borders on both sides (for better visual clarity) or just at the beginning. Texy can handle both variants. + +Syntax ID `heading/surrounded` | [HeadingModule |configuration#headingmodule] + + +Styling Headings +---------------- + +You can add [#modifiers] to any heading. This allows you to assign it a specific CSS class for styling or a unique ID that you can then link to. + +```texy +Heading with red color .[red-heading] +​========================================== + +### Heading with a unique ID for linking .[#contact] +``` + + +Automatic Anchors for Easy Navigation +------------------------------------- + +Don't want to come up with an ID for every heading manually? Texy can do it for you! In the configuration, you can enable automatic ID generation for all headings. This is incredibly useful for directly linking to specific sections. + +```php +// Enable automatic ID generation +$texy->headingModule->generateID = true; + +// Optionally set a prefix for generated IDs (e.g., "toc-") +$texy->headingModule->idPrefix = 'toc-'; +``` + +With this setting, the heading `## My Chapter` will automatically get an ID like `id="toc-my-chapter"` without you having to write anything extra. + + +Lists +===== + + +Bulleted Lists +-------------- + +For a quick list of items where the order doesn't matter, a bulleted list is perfect. Just start each line with a hyphen `-`, an asterisk `*`, or a plus sign `+`, followed by a space. All three characters work the same, so you can choose the one you prefer. + +```texy +What needs to be bought: + +- Milk +- Bread +* Eggs ++ Butter +``` + +ID syntaxe `list` | [ListModule |configuration#listmodule] + + +Numbered Lists +-------------- + +Texy supports various numbering styles: + +| `1.` | Arabic numerals (with a period) +| `1)` | Arabic numerals (with a parenthesis) +| `a)` | Lowercase letters of the alphabet +| `A)` | Uppercase letters of the alphabet +| `I)` | Roman numerals + +The beauty of this is that you don't have to worry about correct numbering at all. Even if you number all the lines with a one, Texy will automatically renumber them for you. This is a huge advantage when you later need to add, delete, or move an item. + + +Nested and Combined Lists +------------------------- + +The power of lists truly shines when you combine and nest them. This allows you to create clear, multi-level structures. You create nesting simply by indenting the line by at least **two spaces** (or one tab). + +```texy +1) First chapter + a) Subchapter 1.1 + - First point + - Second point + b) Subchapter 1.2 +2) Second chapter + - Main idea + - Another note +``` + + +Definition Lists +---------------- + +For cases where you need to create a glossary of terms or clearly explain several terms, a definition list is ideal. + +On the first line, write the term you want to define and end it with a colon. On the following lines, write its definition, indenting each line and starting it with a hyphen `-`. + +```texy +HTML: + - Markup language for creating web pages. + - Abbreviation for HyperText Markup Language. + +CSS: + - Language for describing the presentation (styling) of pages. + - Abbreviation for Cascading Style Sheets. +``` + +Syntax ID `list/definition` | [ListModule |configuration#listmodule] + + +Styling Lists +------------- + +Just like with other elements in Texy, you can easily add [#modifiers] to lists to change their appearance. + +**Entire list:** Write the modifier on the line **before** the start of the list. + +```texy +.[colored-list] +- First item +- Second item +``` + +**Individual item:** Add the modifier to the **end** of the line of the given item or definition term. + +```texy +- Regular item +- This item is important! .{font-weight: bold} +- Another regular item +``` + + +Images +====== + +The basic syntax is very simple. Just enclose the path to the image (whether a local file or a URL) in square brackets with an asterisk: + +```texy +[* image.jpg *] +[* https://domain.com/logo.png *] +``` + +Often you will want the text to wrap around the image. For this, there are simple alignment tags that are inserted before the closing bracket: + +```texy +[* image.jpg <] This text will flow smoothly around the image from the right side. + +[* image.jpg >] In this case, the text will instead flow around the image from the left side. + +[* large-image.jpg <>] +This text will continue below the centered image. +``` + +A properly inserted image should also have "alternative text," which is displayed if the image fails to load. Using a [modifier|#modifiers], you can add this text and other elements for styling. + +```texy +[* landscape-photo.jpg .(A beautiful mountain landscape at sunset)[main-photo] *] +``` + + +Image Dimensions +---------------- + +Texy can automatically detect the dimensions of local images (if the `$texy->imageModule->fileRoot` path is set) and add them to the HTML, which speeds up page loading. However, if you want to set the dimensions manually, you have several options: + +| `[* img.jpg 150x100 *]` | Exact width 150px and height 100px +| `[* img.jpg 150 *]` | Width will be 150px, height will be automatically calculated while maintaining the aspect ratio +| `[* img.jpg ?x100 *]` | Height will be 100px, width will be automatically calculated + + +Clickable Images +---------------- + +Do you want a large image to be displayed when a small thumbnail is clicked? Or for an image to link to another page? Just add a colon and the target URL after the image syntax. + +```texy +[* thumbnail.jpg *]:large.jpg +[* nette-logo.png *]:https://nette.org +``` + +For galleries, there is also a handy shortcut `::`. This automatically creates a link to the same file located at `$texy->imageModule->linkedRoot`. + + +Visible Caption Below the Image +------------------------------- + +If you want to add a visible caption under an image (e.g., the author's name or a description of the scene), write three asterisks `***` and the caption text after it. Texy will automatically create a semantically correct HTML structure `<figure>` and `<figcaption>` from this. + +```texy +[* photo.jpg <> *] *** This is a caption. It can also contain **other formatting**. +``` + + +Organizing Images with References +--------------------------------- + +If you use one image multiple times in the text or want to have all image definitions neatly in one place, you can use references. In the text, you use only a placeholder name, and at the end of the file, you define what this name means. + +```texy +In our logo [* company-logo *] you can see the symbol of our vision. + +​[* company-logo *]: /images/logo.svg 200x50 .(Our company logo) +``` + +This approach significantly clarifies the main text and simplifies image management. + +Syntax ID `image/definition` | [ImageModule |configuration#imagemodule] + + +Preformatted text +================= + +In Texy, you can easily insert blocks of code or any preformatted text where you want to ensure it is displayed exactly as you write it—including all spaces and line breaks. This is ideal for examples of source code, logs, or ASCII art. + +To insert such a block, use the `/--` and `\--` delimiters: + +```texy +/-- +function hello() { + echo 'Hello World'; +} +\-- +``` + +To make your code even more readable, you can tell Texy which programming language it is written in and create a handler that, for example, syntax highlights it, see the "example":custom-handlers#syntax-highlighting. Just add the keyword `code` and the language name after the initial `/--` tag: + +```texy +/--code javascript +console.log('JavaScript'); +\-- + +/--code html +<div>This is HTML code</div> +\-- +``` + + +Content Blocks (divs) +===================== + +Texy allows you to create generic `<div>` blocks, thanks to which you can easily group content into logical units and then style them. + +You create a block using the `/--div` and `\--` tags. In addition, you can easily add [#modifiers]: + +```texy +/--div .[important] +## Important Notice + +This text will be enclosed in a `<div class="important">` block. +This allows you to style it with CSS to make it stand out. +\-- +``` + +The power of `<div>` blocks also lies in the ability to nest them. This allows you to create even more complex structures directly in Texy without having to write HTML manually. + +```texy +/--div .[outer] + This is the outer block. + + /--div .[inner] + And this is a nested, inner block. + \-- + + Here we are back in the outer block. +\-- +``` +Thanks to this simple syntax, you can keep your content clear and semantically well-structured. + + +Disabling Formatting +==================== + +Sometimes it can be useful to "turn off" Texy for a moment and insert a piece of text where Texy should not process its tags. + +If you need to insert a more complex HTML structure without Texy parsing the tags, use the `/--html` block: + +```texy +/--html +<em>This text will be processed as HTML, so it will be in italics.</em> + +**But Texy ignores these asterisks, so they won't be bold.** +\-- +``` + +If you want to display text exactly as it is written, ignoring all tags (both Texy and HTML), use the `/--text` block. Everything inside this block will be displayed as plain text. + +```texy +/--text +<em>This text will be displayed with the tags, but it will not be in italics.</em> + +**This won't be bold either.** +\-- +``` + +But what if you don't want to disable Texy for an entire block of text, but just for a short phrase in the middle of a sentence? For these cases, there is an elegant and quick solution: wrap the text in **double apostrophes** `''`: + +```texy +If you want to show how to write bold text, you would write: The syntax is ''**bold text**''. +``` + +The result will not be bold text; instead, the string `**bold text**` will be printed literally. + + +Tables +====== + +To create a table, start each row with a `|` character and also separate the individual cells with this character. Texy will take care of the alignment and correct HTML on its own. + +```texy +| Jan | Novák | Praha +| Eva | Svobodová | Brno +``` + +The result will be a clear and correctly formatted table. + +Syntax ID `table` | [TableModule |configuration#tablemodule] + + +Table Header +------------ + +Every proper table should have a header that describes what is in each column. You create the header by separating it from the rest of the table with a line containing hyphens `-`. + +```texy +| Name | Age | City +|----------|-----|------- +| Jan | 25 | Prague +| Eva | 30 | Brno +``` + +Alternatively, you can define headers for individual rows (for example, if you have labels in the first column). You achieve this by adding an asterisk `*` immediately after the initial `|`. + +```texy +|* Name | Jan | Eva +|* Age | 25 | 30 +|* City | Praha | Brno +``` + + +Merging Cells +------------- + +Sometimes it is necessary to merge several cells together, either in columns or in rows. + +**Merging columns:** For horizontal cell merging, simply omit the separator and use a double vertical bar `||` instead. The cell to the right will be merged with the cell to its left. + +```texy +| First Name || Age +|---------------------------- +| Jan | Novák | 25 +``` + +**Merging rows:** For vertical cell merging, use the caret symbol `^` in the cell you want to attach to the one above it. This tells Texy: "Merge this cell with the one above it." + +```texy +| Month | Sales | +|---------|---------- +| January | 150 pcs | +| February | ^| +| March | 210 pcs | +``` + +In this example, the cell with sales for January and February will be merged. + +This way, several cells can be merged across rows and columns: + +```texy +| First Name | Last Name | Age +|---------------------------- +| Bill || 50 +| ^| 52 +| Jim | Beam | 70 +``` + + +Styling Tables +-------------- + +As with other elements in Texy, you can also add [#modifiers] to tables and their parts to change their appearance (e.g., CSS classes, styles, or IDs). + +**Entire table:** Place the modifier for the entire table on a separate line just before it. + +```texy +.[data-table table-striped] +| Header 1 | Header 2 +|------------|------------ +| data | data +``` + +**Individual rows:** If you want to style a specific row, add the modifier to its end. + +```texy +| Name | Status +|-------|-------------- +| Petr | Approved +| Jana | Rejected | .{background: #ffdddd} +``` + +**Individual columns:** To style an entire column, insert the modifier at the beginning of the first cell of that column. + +```texy +| Name | .> Price | In Stock +|----------------|-----------|--------- +| Product A | 1 200 Kč | Yes +| Product B | 850 Kč | No +``` + +**Specific cell:** Write the modifier for a single cell directly in it, usually at the end of its content. + +```texy +| Task | Status +|----------------------|------------------------------------- +| Prepare documents | Done +| Check data | In progress .{color: orange; font-weight: bold} +``` + + +Blockquotes +=========== + +If you need to emphasize someone else's idea in your text, cite a source, or just visually separate a block of text, simply start the line with the `>` character. + +```texy +> This is a blockquote. It serves to highlight an important idea or an excerpt from another source. +``` + +A blockquote doesn't have to be just one paragraph. If you want to continue with another paragraph within the same blockquote, simply insert a blank line that also starts with the `>` character. + +```texy +> This is the first paragraph of the blockquote. Lorem ipsum dolor sit amet. +> +> And this is the second paragraph, which still belongs to the same blockquote. +> This way you can structure even longer texts. +``` + +Texy even supports nested blockquotes, which is useful if you are quoting someone who is quoting someone else. For each additional level of nesting, add another `>` character. + +```texy +> This is the outer, main blockquote. +> +> > And this is a nested, second-level blockquote. +> +> Here the text returns to the main blockquote. +``` + +Inside blockquotes, you can of course use other formatting, such as **bold text** or *italics*. + + +Horizontal Rules +================ + +Sometimes it is necessary to visually divide the text. A horizontal rule is great for this. On a separate line, write three or more hyphens `---` or asterisks `***`. + +```texy +The first part of the text on a certain topic. + +*** + +The second part of the text, which begins after the visual separation. +``` + +To create a horizontal rule, it **must be preceded by a blank line**. If you were to write it immediately after the text, Texy would think you wanted to create an underlined heading. + +Syntax ID `horizline` | [HorizLineModule |configuration#horizlinemodule] + + +Typography +========== + +The power of Texy lies not only in formatting, but also in automatic typographic corrections. Texy takes care of the details that make text professional and easy to read, all according to Czech typographic rules. This allows you to focus solely on the content. + +**Quotes:** You don't have to worry about how to type correct typographic quotes on the keyboard. Texy will do it for you. + +It automatically converts classic ''"typewriter quotes"'' into the correct English “quotes” and nested ‘quotes’. The type of quotes depends on the locale setting: + +```php +$texy->typographyModule->locale = 'cs'; // Czech +$texy->typographyModule->locale = 'en'; // English +``` + +**Dashes and hyphens:** It intelligently recognizes when to use a short hyphen (in hyphenated words) and when to use a longer en dash—for example, in ranges (10–15) or between words. + +```texy +10-15 → 10–15 (en dash for ranges) +czech-slovak → czech-slovak (hyphen remains) +word -- word → word – word (en dash between words) +word --- word → word — word (em dash) +``` + +**Non-breaking spaces**: One of the biggest advantages is the automatic insertion of non-breaking spaces where needed. This prevents single-letter words (like `a` or `I`) from being left alone at the end of a line, which is a common typographic error. + +```texy +// You write: +I visited a castle in Prague. + +// Texy ensures that "a" never remains at the end of a line: +I visited a castle in Prague. +``` + +It also takes care of correct spacing in phone numbers or dates to prevent them from breaking. + +```texy ++420 776 552 046 → +420 776 552 046 (all spaces non-breaking) +``` + +**Automatic symbols:** Texy also makes it easier for you to write frequently used symbols. + +| You write | Texy generates | Description +|----- +| `...` | … | Ellipsis +| `(c)` | © | Copyright +| `(r)` | ® | Registered trademark +| `(tm)` | ™ | Trademark +| `10 x 5` | 10 × 5 | Multiplication sign +| `+-` | ± | Plus-minus +| `<-` `->` `<->` | ← → ↔ | Arrows + +Thanks to these automatic adjustments, your text will always look professional without you having to know complex keyboard shortcuts or HTML entities. + + +Hyphenation of Long Words +------------------------- + +You know it—a long word appears in the text, such as "antidisestablishmentarianism," and on a narrow mobile phone screen, it breaks the entire page layout. Fortunately, Texy offers an elegant solution: it can insert invisible "soft hyphens" (`­`) into the word. These hyphens tell the browser where (between syllables) it can safely break the word if it doesn't fit at the end of the line. If the word fits on the line, the hyphens remain hidden and nothing happens. + +```latte +antidisestablish­mentarianism +``` + +Thanks to this, your text will always adapt beautifully to any screen width without unwanted horizontal scrolling. + +Because this feature is not suitable for all types of websites, it is disabled by default. You can activate it in the configuration: + +```php +$texy->allowed['longwords'] = true; + +// Set the minimum word length from which to hyphenate (e.g., 20 characters) +$texy->longWordsModule->wordLimit = 20; +``` + +Syntax ID `longwords` | [LongWordsModule |configuration#long-wordsmodule] + + +Emoticons +========= + +Texy can automatically convert classic text smileys into graphical emoticons. Simply type the smiley as you are used to, and Texy will take care of the rest. + +| You write | Texy generates +|----- +| `:-)` | 🙂 +| `:-(` | ☹ +| `;-)` | 😉 +| `:-D` | 😀 +| `:-*` | 😘 + +Depending on the configuration, Texy can convert these shortcuts either to modern Unicode emoji (as in the table above) or to small images (`<img>`). + +To prevent unwanted conversions, for example in technical texts, this feature is disabled by default. If you want to use it, you just need to enable it: + +```php +$texy->allowed['emoticon'] = true; +``` + +More information about available emoticons and configuration options can be found in the [EmoticonModule configuration |configuration#emoticonmodul]. + +Syntax ID `emoticon` | [EmoticonModule |configuration#emoticonmodule] diff --git a/texy/en/try-settings.texy b/texy/en/try-settings.texy new file mode 100644 index 0000000000..0b8706a6a8 --- /dev/null +++ b/texy/en/try-settings.texy @@ -0,0 +1,55 @@ +Demo Configuration +****************** + +This setting is used in [demo | https://fiddle.nette.org/texy/]: + +/--php +$texy = new Texy\Texy; + +$texy->imageModule->root = '/images/'; +$texy->imageModule->linkedRoot = '/images/'; +$texy->headingModule->generateID = true; + +// syntax highlighting +$texy->addHandler('block', 'blockHandler'); +\-- + +The handler uses Prism.js to highlight syntax: + +/--php +function blockHandler( + Texy\HandlerInvocation $invocation, + string $blocktype, + string $content, + string $lang, + Texy\Modifier $modifier +): Texy\HtmlElement +{ + if ($blocktype !== 'block/code') { + // nothing to do + return $invocation->proceed(); + } + + $texy = $invocation->getTexy(); + $elPre = Texy\HtmlElement::el('pre'); + if ($modifier) { + $modifier->decorate($texy, $elPre); + } + $elPre->attrs['class'] = 'language-' . $lang; + $content = $texy->protect(htmlspecialchars($content), $texy::CONTENT_BLOCK); + $elPre->create('code', $content); + return $elPre; +} +\-- + +In addition, when the conversion is complete, some characters are replaced by entities in the text to make them more visible: + +/--php +$html = $texy->process($text); + +$html = str_replace( + ["\xc2\xa0", "\xc2\xad", "\xe2\x80\x93", "\xe2\x80\x94"], + [' ', '­', '–', '—'], + $html +); +\-- diff --git a/texy/files/image.gif b/texy/files/image.gif new file mode 100644 index 0000000000..b99eabeaf8 Binary files /dev/null and b/texy/files/image.gif differ diff --git a/texy/meta.json b/texy/meta.json new file mode 100644 index 0000000000..27991fd5a8 --- /dev/null +++ b/texy/meta.json @@ -0,0 +1,5 @@ +{ + "version": "3.x", + "repo": "dg/texy", + "composer": "texy/texy" +} diff --git a/tokenizer/cs/@home.texy b/tokenizer/cs/@home.texy index bf178a5fd2..1ff068a35d 100644 --- a/tokenizer/cs/@home.texy +++ b/tokenizer/cs/@home.texy @@ -203,3 +203,4 @@ Poslední metoda `reset()` vrací kurzor na začátek, takže můžete opakovat {{leftbar: utils:@left-menu}} +{{sitename: Nette Dokumentace}} diff --git a/tokenizer/en/@home.texy b/tokenizer/en/@home.texy index 19d1a378a3..165db1ca95 100644 --- a/tokenizer/en/@home.texy +++ b/tokenizer/en/@home.texy @@ -203,3 +203,4 @@ And the last method `reset()` resets the cursor, so you can iterate the token st {{leftbar: utils:@left-menu}} +{{sitename: Nette Documentation}} diff --git a/tracy/bg/@meta.texy b/tracy/bg/@meta.texy new file mode 100644 index 0000000000..c9a4dccb91 --- /dev/null +++ b/tracy/bg/@meta.texy @@ -0,0 +1 @@ +{{sitename: Документация на Tracy}} diff --git a/tracy/cs/@meta.texy b/tracy/cs/@meta.texy new file mode 100644 index 0000000000..97ca57995d --- /dev/null +++ b/tracy/cs/@meta.texy @@ -0,0 +1 @@ +{{sitename: Tracy Dokumentace}} diff --git a/tracy/cs/guide.texy b/tracy/cs/guide.texy index 23343cc56a..8ce469764f 100644 --- a/tracy/cs/guide.texy +++ b/tracy/cs/guide.texy @@ -161,7 +161,7 @@ try { } catch (Exception $e) { Debugger::log($e); // logovat lze i výjimku // nebo - Debugger::log($e, Debugger::ERROR); odešle i e-mailovou notifikaci + Debugger::log($e, Debugger::ERROR); // odešle i e-mailovou notifikaci } ``` diff --git a/tracy/cs/open-files-in-ide.texy b/tracy/cs/open-files-in-ide.texy index 37ce131750..d3b8e22605 100644 --- a/tracy/cs/open-files-in-ide.texy +++ b/tracy/cs/open-files-in-ide.texy @@ -135,10 +135,10 @@ V Google Chrome od verze 77 již neuvidíte zatržítko „Tento typ odkazů vž ``` Windows Registry Editor Version 5.00 -[HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Google\Chrome\URLWhitelist] -"123"="editor://*" +[HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Google\Chrome] +"AutoLaunchProtocolsFromOrigins"="[{\"allowed_origins\": [\"*\"],\"protocol\": \"editor\"}]" ``` -Importujte jej dvojitým kliknutím a restartujte prohlížeč Chrome. +Importujte jej dvojitým kliknutím a restartujte prohlížeč Chrome. Politika `AutoLaunchProtocolsFromOrigins` úplně potlačí potvrzovací dialog prohlížeče. Skript `install.cmd` toto nastavení provádí automaticky, a to včetně zakomentovaného řádku pro Vivaldi (stejná politika ve větvi `HKLM\SOFTWARE\Policies\Vivaldi`). S případnými dotazy nebo připomínkami se prosím obraťte na [fórum |https://forum.nette.org]. diff --git a/tracy/cs/stopwatch.texy b/tracy/cs/stopwatch.texy index 8120595cfa..95b8cf24b4 100644 --- a/tracy/cs/stopwatch.texy +++ b/tracy/cs/stopwatch.texy @@ -29,7 +29,7 @@ $pageElapsed = Debugger::timer('page-generating'); ```php Debugger::timer(); // zapne stopky -... // časově náročná operace +// ... časově náročná operace echo Debugger::timer(); // vypíše uplynulý čas v sekundách ``` diff --git a/tracy/de/@meta.texy b/tracy/de/@meta.texy new file mode 100644 index 0000000000..6ed3b370dd --- /dev/null +++ b/tracy/de/@meta.texy @@ -0,0 +1 @@ +{{sitename: Tracy Dokumentation}} diff --git a/tracy/el/@meta.texy b/tracy/el/@meta.texy new file mode 100644 index 0000000000..93980491e0 --- /dev/null +++ b/tracy/el/@meta.texy @@ -0,0 +1 @@ +{{sitename: Tracy Τεκμηρίωση}} diff --git a/tracy/en/@meta.texy b/tracy/en/@meta.texy new file mode 100644 index 0000000000..c0491c0f50 --- /dev/null +++ b/tracy/en/@meta.texy @@ -0,0 +1 @@ +{{sitename: Tracy Documentation}} diff --git a/tracy/en/open-files-in-ide.texy b/tracy/en/open-files-in-ide.texy index 2c8d9112ba..53c2b863c7 100644 --- a/tracy/en/open-files-in-ide.texy +++ b/tracy/en/open-files-in-ide.texy @@ -135,10 +135,10 @@ Starting from Google Chrome version 77 you will no longer see the checkbox “Al ``` Windows Registry Editor Version 5.00 -[HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Google\Chrome\URLWhitelist] -"123"="editor://*" +[HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Google\Chrome] +"AutoLaunchProtocolsFromOrigins"="[{\"allowed_origins\": [\"*\"],\"protocol\": \"editor\"}]" ``` -Import it by double clicking and restart Chrome. +Import it by double clicking and restart Chrome. The `AutoLaunchProtocolsFromOrigins` policy fully suppresses the browser confirmation dialog. The `install.cmd` script sets this automatically, including a commented-out line for Vivaldi (same policy under `HKLM\SOFTWARE\Policies\Vivaldi`). For further questions or suggestions, please visit the [forum |https://forum.nette.org]. diff --git a/tracy/en/stopwatch.texy b/tracy/en/stopwatch.texy index 6546ac6e71..7608a61b03 100644 --- a/tracy/en/stopwatch.texy +++ b/tracy/en/stopwatch.texy @@ -29,7 +29,7 @@ $pageElapsed = Debugger::timer('page-generating'); ```php Debugger::timer(); // runs the timer -... // some time-consuming operation +// ... some time-consuming operation echo Debugger::timer(); // elapsed time in seconds ``` diff --git a/tracy/es/@meta.texy b/tracy/es/@meta.texy new file mode 100644 index 0000000000..891977ea09 --- /dev/null +++ b/tracy/es/@meta.texy @@ -0,0 +1 @@ +{{sitename: Tracy Documentación}} diff --git a/tracy/fr/@meta.texy b/tracy/fr/@meta.texy new file mode 100644 index 0000000000..ccb3776c80 --- /dev/null +++ b/tracy/fr/@meta.texy @@ -0,0 +1 @@ +{{sitename: Documentation Tracy}} diff --git a/tracy/hu/@meta.texy b/tracy/hu/@meta.texy new file mode 100644 index 0000000000..59d1cb7017 --- /dev/null +++ b/tracy/hu/@meta.texy @@ -0,0 +1 @@ +{{sitename: Tracy dokumentáció}} diff --git a/tracy/it/@meta.texy b/tracy/it/@meta.texy new file mode 100644 index 0000000000..80acea0506 --- /dev/null +++ b/tracy/it/@meta.texy @@ -0,0 +1 @@ +{{sitename: Documentazione Tracy}} diff --git a/tracy/ja/@meta.texy b/tracy/ja/@meta.texy new file mode 100644 index 0000000000..8666d0e5f6 --- /dev/null +++ b/tracy/ja/@meta.texy @@ -0,0 +1 @@ +{{sitename: Tracy ドキュメンテーション}} diff --git a/tracy/pl/@meta.texy b/tracy/pl/@meta.texy new file mode 100644 index 0000000000..74de69cd94 --- /dev/null +++ b/tracy/pl/@meta.texy @@ -0,0 +1 @@ +{{sitename: Dokumentacja Tracy}} diff --git a/tracy/pt/@meta.texy b/tracy/pt/@meta.texy new file mode 100644 index 0000000000..5df23a7829 --- /dev/null +++ b/tracy/pt/@meta.texy @@ -0,0 +1 @@ +{{sitename: Documentação Tracy}} diff --git a/tracy/ro/@meta.texy b/tracy/ro/@meta.texy new file mode 100644 index 0000000000..d9fe86594e --- /dev/null +++ b/tracy/ro/@meta.texy @@ -0,0 +1 @@ +{{sitename: Documentație Tracy}} diff --git a/tracy/ru/@meta.texy b/tracy/ru/@meta.texy new file mode 100644 index 0000000000..22a9b5fa46 --- /dev/null +++ b/tracy/ru/@meta.texy @@ -0,0 +1 @@ +{{sitename: Документация Tracy}} diff --git a/tracy/sl/@meta.texy b/tracy/sl/@meta.texy new file mode 100644 index 0000000000..c2ee8bbc08 --- /dev/null +++ b/tracy/sl/@meta.texy @@ -0,0 +1 @@ +{{sitename: Tracy Dokumentacija}} diff --git a/tracy/tr/@meta.texy b/tracy/tr/@meta.texy new file mode 100644 index 0000000000..272c7f354c --- /dev/null +++ b/tracy/tr/@meta.texy @@ -0,0 +1 @@ +{{sitename: Tracy Dokümantasyonu}} diff --git a/tracy/uk/@meta.texy b/tracy/uk/@meta.texy new file mode 100644 index 0000000000..f50e3b03b0 --- /dev/null +++ b/tracy/uk/@meta.texy @@ -0,0 +1 @@ +{{sitename: Документація Tracy}} diff --git a/utils/bg/@meta.texy b/utils/bg/@meta.texy new file mode 100644 index 0000000000..57804a1127 --- /dev/null +++ b/utils/bg/@meta.texy @@ -0,0 +1 @@ +{{sitename: Документация на Nette}} diff --git a/utils/bg/arrays.texy b/utils/bg/arrays.texy index d73bfc5b6e..c2f5884283 100644 --- a/utils/bg/arrays.texy +++ b/utils/bg/arrays.texy @@ -360,8 +360,8 @@ pick(array &$array, string|int $key, ?mixed $default=null): mixed .[method] Връща и премахва стойността на елемент от масива. Ако не съществува, хвърля изключение или връща стойността `$default`, ако е посочена. ```php -$array = [1 => 'foo', null => 'bar']; -$a = Arrays::pick($array, null); +$array = [1 => 'foo', 'x' => 'bar']; +$a = Arrays::pick($array, 'x'); // $a = 'bar' $b = Arrays::pick($array, 'not-exists', 'foobar'); // $b = 'foobar' diff --git a/utils/cs/@meta.texy b/utils/cs/@meta.texy new file mode 100644 index 0000000000..462d9add80 --- /dev/null +++ b/utils/cs/@meta.texy @@ -0,0 +1 @@ +{{sitename: Nette Dokumentace}} diff --git a/utils/cs/arrays.texy b/utils/cs/arrays.texy index 9351bba355..baa1c82d10 100644 --- a/utils/cs/arrays.texy +++ b/utils/cs/arrays.texy @@ -360,8 +360,8 @@ pick(array &$array, string|int $key, ?mixed $default=null): mixed .[method] Vrátí a odstraní hodnotu prvku z pole. Pokud neexistuje, vyhodí výjimku, nebo vrátí hodnotu `$default`, pokud je uvedena. ```php -$array = [1 => 'foo', null => 'bar']; -$a = Arrays::pick($array, null); +$array = [1 => 'foo', 'x' => 'bar']; +$a = Arrays::pick($array, 'x'); // $a = 'bar' $b = Arrays::pick($array, 'not-exists', 'foobar'); // $b = 'foobar' diff --git a/utils/cs/datetime.texy b/utils/cs/datetime.texy index 6b2788d3e1..f685af7909 100644 --- a/utils/cs/datetime.texy +++ b/utils/cs/datetime.texy @@ -4,6 +4,9 @@ Datum a čas .[perex] [api:Nette\Utils\DateTime] je třída, která rozšiřuje nativní [php:DateTime] o další funkce. +Oproti svému předchůdci je striktní. Zatímco PHP **tiše akceptuje** nesmyslná data jako `0000-00-00` (převede na `-0001-11-30`) nebo `2024-02-31` (převede na `2024-03-02`), `Nette\Utils\DateTime` v takových případech vyhodí výjimku. + +Zároveň **opravuje chování** při přechodu na letní/zimní čas, kdy v nativním PHP může přičtení relativního času (např. `+100 minutes`) "vést k dřívějšímu výslednému času":https://phpfashion.com/cs/100-minut-je-mene-nez-50-paradoxy-php-pri-zmene-casu než přičtení kratšího úseku (např. `+50 minutes`). Nette zajišťuje, že aritmetika funguje intuitivně a `+100 minutes` je vždy více než `+50 minutes`. Instalace: @@ -46,6 +49,17 @@ DateTime::createFromFormat('d.m.Y', '26.02.1994', 'Europe/London'); ``` +static relativeToSeconds(string $str): int .[method]{data-version:4.0.7} +------------------------------------------------------------------------ +Převede relativní časový údaj na sekundy. Hodí se pro převod časů jako `5 minutes` nebo `2 hours` na číselnou hodnotu. + +```php +DateTime::relativeToSeconds('1 minute'); // 60 +DateTime::relativeToSeconds('10 minutes'); // 600 +DateTime::relativeToSeconds('-1 hour'); // -3600 +``` + + modifyClone(string $modify=''): static .[method] ------------------------------------------------ Vytvoří kopii s upraveným časem. diff --git a/utils/cs/filesystem.texy b/utils/cs/filesystem.texy index 1f68e7313b..0b3e31e9ac 100644 --- a/utils/cs/filesystem.texy +++ b/utils/cs/filesystem.texy @@ -209,6 +209,6 @@ class AnyClassUsingFileSystem return $this->fileSystem->read(/* ... */); } - ... + // ... } ``` diff --git a/utils/cs/helpers.texy b/utils/cs/helpers.texy index 2b5bcbe27e..49e37ebaed 100644 --- a/utils/cs/helpers.texy +++ b/utils/cs/helpers.texy @@ -84,3 +84,14 @@ Helpers::getSuggestion($items, 'fo'); // 'foo' Helpers::getSuggestion($items, 'barr'); // 'bar' Helpers::getSuggestion($items, 'baz'); // 'bar', ne 'baz' ``` + + +splitClassName(string $name): array .[method]{data-version:4.0.10} +------------------------------------------------------------------ + +Rozdělí celý název třídy v PHP na jmenný prostor a zkrácený název třídy. Vrací pole dvou řetězců, kde první prvek je namespace a druhý název třídy. + +```php +Helpers::splitClassName('Nette\Utils\Helpers'); // ['Nette\Utils', 'Helpers'] +Helpers::splitClassName('Foo'); // ['', 'Foo'] +``` diff --git a/utils/cs/iterables.texy b/utils/cs/iterables.texy index 77af7696df..ebf73344b7 100644 --- a/utils/cs/iterables.texy +++ b/utils/cs/iterables.texy @@ -140,6 +140,27 @@ $memoized = Iterables::memoize($iterator); Tato metoda je užitečná v situacích, kdy potřebujete vícekrát projít stejnou sadu dat, ale původní iterátor neumožňuje opakovanou iteraci nebo by opakované procházení bylo nákladné (např. při čtení dat z databáze nebo souboru). +repeatable(callable $factory): IteratorAggregate .[method]{data-version:4.0.10} +------------------------------------------------------------------------------- + +Umožňuje opakovanou iteraci objektů, které to běžně nedovolují, typicky [PHP generátorů |https://www.php.net/manual/en/language.generators.overview.php]. Metoda `repeatable()` tento problém elegantně řeší: místo samotného iterátoru jí předáte funkci, která iterátor vytváří. Tato továrna je pak zavolána automaticky při každém novém průchodu cyklem. + +```php +// Běžný generátor, který nelze projít dvakrát +$generator = function () { + yield 'A'; + yield 'B'; +}; + +$iterator = Iterables::repeatable($generator); + +foreach ($iterator as $v) echo $v; // Vypíše: AB +foreach ($iterator as $v) echo $v; // Vypíše: AB (generátor se spustil znovu) +``` + +Tato metoda je alternativou k [#memoize()] v situacích, kdy pracujete s **velkým objemem dat**, jelikož `repeatable()` si data neukládá, ale při každém průchodu je generuje znovu. + + some(iterable $iterable, callable $predicate): bool .[method] ------------------------------------------------------------- diff --git a/utils/cs/type.texy b/utils/cs/type.texy index d4c539ee67..f2af19e5f8 100644 --- a/utils/cs/type.texy +++ b/utils/cs/type.texy @@ -2,8 +2,13 @@ PHP Typ ******* .[perex] -[api:Nette\Utils\Type] je třída pro práci s datovými typy PHP. +[api:Nette\Utils\Type] reprezentuje datový typ PHP. Slouží k analýze, porovnávání a manipulaci s typy, ať už pocházejí z řetězce nebo z reflexe. +PHP má dnes velmi bohatý typový systém: od skalárních typů (`int`, `string`) přes objekty a rozhraní až po složené typy (union `A|B`, intersection `A&B` nebo disjunktivní normální formy `(A&B)|D`). Navíc existují speciální typy jako `void`, `never`, `mixed` nebo relativní `self` či `static`. + +Práce s těmito typy nativně, zejména přes `ReflectionType`, je často zdlouhavá, protože musíte rekurzivně rozlišovat mezi `ReflectionNamedType`, `ReflectionUnionType` a dalšími objekty. Třída `Nette\Utils\Type` toto vše zapouzdřuje a poskytuje **jednotné a srozumitelné API** pro práci s jakýmkoliv typem, který PHP podporuje. + +Umožňuje například snadno zjistit, zda jeden typ [akceptuje|#allows] druhý (kompatibilita), [rozšiřovat typy|#with] nebo převádět reflexe na čitelný zápis. Instalace: @@ -45,6 +50,25 @@ echo $type; // 'Foo|Bar' ``` +fromValue(mixed $value): Type .[method]{data-version:4.0.10} +------------------------------------------------------------ + +Statická metoda, která vytvoří objekt Type podle typu předané hodnoty. + +```php +$type = Type::fromValue('hello'); // 'string' +$type = Type::fromValue(123); // 'int' +$type = Type::fromValue(new stdClass); // 'stdClass' +``` + +Pro resources vrací `mixed`, protože PHP typ `resource` nezná. U anonymních tříd vrací nejbližšího předka nebo typ `object`. + +```php +$obj = new class extends Foo { }; +$type = Type::fromValue($obj); // 'Foo' +``` + + getNames(): (string|array)[] .[method] -------------------------------------- @@ -183,8 +207,8 @@ $type->isClassKeyword(); // false ``` -allows(string $type): bool .[method] ------------------------------------- +allows(string|Type $type): bool .[method] +----------------------------------------- Metoda `allows()` ověřuje kompatibilitu typů. Například umožní zjistit, jestli hodnota určitého typu by mohla být předaná jako parametr. @@ -197,3 +221,24 @@ $type->allows('Foo'); // false $type = Type::fromString('mixed'); $type->allows('null'); // true ``` + + +with(string|Type $type): Type .[method]{data-version:4.0.10} +------------------------------------------------------------ + +Vrací objekt Type, který akceptuje jak původní typ, tak i nově přidaný. Vytváří tzv. union type. + +Metoda je chytrá a typy zbytečně nezdvojuje. Pokud přidáte typ, který je již obsažen, nebo je nadmnožinou stávajícího typu (např. přidání `mixed` k `string`), vrátí se zjednodušený výsledek. + +```php +$type = Type::fromString('string'); + +// Rozšíření na nullable string +echo $type->with('null'); // '?string' + +// Vytvoření union typu +echo $type->with('int'); // 'string|int' + +// Přidání typu, který "přebije" vše ostatní +echo $type->with('mixed'); // 'mixed' +``` diff --git a/utils/de/@meta.texy b/utils/de/@meta.texy new file mode 100644 index 0000000000..b3b806b2ca --- /dev/null +++ b/utils/de/@meta.texy @@ -0,0 +1 @@ +{{sitename: Nette Dokumentation}} diff --git a/utils/de/arrays.texy b/utils/de/arrays.texy index 9167248df2..472f4b1c8e 100644 --- a/utils/de/arrays.texy +++ b/utils/de/arrays.texy @@ -360,8 +360,8 @@ pick(array &$array, string|int $key, ?mixed $default=null): mixed .[method] Gibt den Wert eines Elements aus dem Array zurück und entfernt ihn. Wenn er nicht existiert, wird eine Ausnahme geworfen, oder der Wert `$default` zurückgegeben, falls angegeben. ```php -$array = [1 => 'foo', null => 'bar']; -$a = Arrays::pick($array, null); +$array = [1 => 'foo', 'x' => 'bar']; +$a = Arrays::pick($array, 'x'); // $a = 'bar' $b = Arrays::pick($array, 'not-exists', 'foobar'); // $b = 'foobar' diff --git a/utils/el/@meta.texy b/utils/el/@meta.texy new file mode 100644 index 0000000000..88e29852c7 --- /dev/null +++ b/utils/el/@meta.texy @@ -0,0 +1 @@ +{{sitename: Nette Τεκμηρίωση}} diff --git a/utils/el/arrays.texy b/utils/el/arrays.texy index 835c2658eb..8fdc7e0860 100644 --- a/utils/el/arrays.texy +++ b/utils/el/arrays.texy @@ -360,8 +360,8 @@ pick(array &$array, string|int $key, ?mixed $default=null): mixed .[method] Επιστρέφει και αφαιρεί την τιμή του στοιχείου από τον πίνακα. Αν δεν υπάρχει, ρίχνει μια εξαίρεση, ή επιστρέφει την τιμή `$default`, αν έχει καθοριστεί. ```php -$array = [1 => 'foo', null => 'bar']; -$a = Arrays::pick($array, null); +$array = [1 => 'foo', 'x' => 'bar']; +$a = Arrays::pick($array, 'x'); // $a = 'bar' $b = Arrays::pick($array, 'not-exists', 'foobar'); // $b = 'foobar' diff --git a/utils/en/@meta.texy b/utils/en/@meta.texy new file mode 100644 index 0000000000..42471908b0 --- /dev/null +++ b/utils/en/@meta.texy @@ -0,0 +1 @@ +{{sitename: Nette Documentation}} diff --git a/utils/en/arrays.texy b/utils/en/arrays.texy index a14be68d17..c6abf68903 100644 --- a/utils/en/arrays.texy +++ b/utils/en/arrays.texy @@ -360,8 +360,8 @@ pick(array &$array, string|int $key, mixed $default=null): mixed .[method] Returns and removes the value of an item with key `$key` from an array. If the item does not exist, it throws an exception, or returns `$default` if provided. ```php -$array = [1 => 'foo', null => 'bar']; -$a = Arrays::pick($array, null); +$array = [1 => 'foo', 'x' => 'bar']; +$a = Arrays::pick($array, 'x'); // $a = 'bar' $b = Arrays::pick($array, 'not-exists', 'foobar'); // $b = 'foobar' diff --git a/utils/en/datetime.texy b/utils/en/datetime.texy index 3fc7cdf0ac..5b00d789d3 100644 --- a/utils/en/datetime.texy +++ b/utils/en/datetime.texy @@ -4,6 +4,9 @@ Date and Time .[perex] [api:Nette\Utils\DateTime] is a class that extends the native [php:DateTime] with additional useful features. +Compared to the native class, it is strict. While PHP **silently accepts** invalid dates like `0000-00-00` (converts to `-0001-11-30`) or `2024-02-31` (converts to `2024-03-02`), `Nette\Utils\DateTime` throws an exception in such cases. + +It also **fixes the behavior** during Daylight Saving Time (DST) transitions, where in native PHP adding a relative time (e.g., `+100 minutes`) can "result in an earlier time":https://phpfashion.com/en/100-minutes-is-less-than-50-php-paradoxes-during-time-changes than adding a shorter period (e.g., `+50 minutes`). Nette ensures that arithmetic works intuitively and `+100 minutes` is always more than `+50 minutes`. Installation: @@ -46,6 +49,17 @@ DateTime::createFromFormat('d.m.Y', '26.02.1994', 'Europe/London'); // create wi ``` +static relativeToSeconds(string $str): int .[method]{data-version:4.0.7} +------------------------------------------------------------------------ +Converts a relative time string to seconds. It is useful for converting times like `5 minutes` or `2 hours` to a numeric value. + +```php +DateTime::relativeToSeconds('1 minute'); // 60 +DateTime::relativeToSeconds('10 minutes'); // 600 +DateTime::relativeToSeconds('-1 hour'); // -3600 +``` + + modifyClone(string $modify=''): static .[method] ------------------------------------------------ Creates a copy with a modified time. diff --git a/utils/en/filesystem.texy b/utils/en/filesystem.texy index 7c66d4c3e3..f8e43ddf3e 100644 --- a/utils/en/filesystem.texy +++ b/utils/en/filesystem.texy @@ -209,6 +209,6 @@ class AnyClassUsingFileSystem return $this->fileSystem->read(/* ... */); } - ... + // ... } ``` diff --git a/utils/en/helpers.texy b/utils/en/helpers.texy index 280cdb8e4c..4c69556b64 100644 --- a/utils/en/helpers.texy +++ b/utils/en/helpers.texy @@ -84,3 +84,14 @@ Helpers::getSuggestion($items, 'fo'); // 'foo' Helpers::getSuggestion($items, 'barr'); // 'bar' Helpers::getSuggestion($items, 'baz'); // 'bar', not 'baz' ``` + + +splitClassName(string $name): array .[method]{data-version:4.0.10} +------------------------------------------------------------------ + +Splits a PHP class name into a namespace and a short class name. Returns an array of two strings where the first is the namespace and the second is the class name. + +```php +Helpers::splitClassName('Nette\Utils\Helpers'); // ['Nette\Utils', 'Helpers'] +Helpers::splitClassName('Foo'); // ['', 'Foo'] +``` diff --git a/utils/en/iterables.texy b/utils/en/iterables.texy index a5f06f8be0..56c86f60d7 100644 --- a/utils/en/iterables.texy +++ b/utils/en/iterables.texy @@ -140,6 +140,27 @@ $memoized = Iterables::memoize($iterator); This method is useful in situations where you need to iterate over the same dataset multiple times, but the original iterator doesn't allow repeated iteration, or re-traversing would be costly (e.g., reading data from a database or file). +repeatable(callable $factory): IteratorAggregate .[method]{data-version:4.0.10} +------------------------------------------------------------------------------- + +Allows repeated iteration of objects that otherwise do not support it, typically [PHP generators |https://www.php.net/manual/en/language.generators.overview.php]. The `repeatable()` method solves this problem elegantly: instead of passing the iterator itself, you pass a function that creates it. This factory is then called automatically during each iteration loop. + +```php +// A standard generator that cannot be iterated twice +$generator = function () { + yield 'A'; + yield 'B'; +}; + +$iterator = Iterables::repeatable($generator); + +foreach ($iterator as $v) echo $v; // Prints: AB +foreach ($iterator as $v) echo $v; // Prints: AB (generator ran again) +``` + +This method is an alternative to [#memoize()] in situations where you are working with **large amounts of data**, since `repeatable()` does not cache data, but generates it again during each iteration. + + some(iterable $iterable, callable $predicate): bool .[method] ------------------------------------------------------------- diff --git a/utils/en/type.texy b/utils/en/type.texy index 08886b2e91..f462bbb31c 100644 --- a/utils/en/type.texy +++ b/utils/en/type.texy @@ -2,8 +2,13 @@ PHP Type ******** .[perex] -[api:Nette\Utils\Type] is a class for working with PHP data types. +[api:Nette\Utils\Type] represents a PHP data type. It is used for analyzing, comparing, and manipulating types, whether obtained from a string or reflection. +PHP currently has a very rich type system: from scalar types (`int`, `string`), through objects and interfaces, to complex types (union `A|B`, intersection `A&B`, or disjunctive normal forms `(A&B)|D`). Additionally, there are special types like `void`, `never`, `mixed`, or relative types `self` and `static`. + +Working with these types natively, especially via `ReflectionType`, is often cumbersome because you must recursively distinguish between `ReflectionNamedType`, `ReflectionUnionType`, and other objects. The `Nette\Utils\Type` class encapsulates all of this and provides a **unified and intuitive API** for working with any type supported by PHP. + +For example, it allows you to easily check if one type [accepts|#allows] another (compatibility), [extend types|#with], or convert reflections into a readable notation. Installation: @@ -45,6 +50,25 @@ echo $type; // 'Foo|Bar' ``` +fromValue(mixed $value): Type .[method]{data-version:4.0.10} +------------------------------------------------------------ + +Static method that creates a Type object based on the type of the passed value. + +```php +$type = Type::fromValue('hello'); // 'string' +$type = Type::fromValue(123); // 'int' +$type = Type::fromValue(new stdClass); // 'stdClass' +``` + +For resources, it returns `mixed`, as PHP does not support the `resource` type. For anonymous classes, it returns the name of the nearest ancestor or `object`. + +```php +$obj = new class extends Foo { }; +$type = Type::fromValue($obj); // 'Foo' +``` + + getNames(): (string|array)[] .[method] -------------------------------------- @@ -183,8 +207,8 @@ $type->isClassKeyword(); // false ``` -allows(string $type): bool .[method] ------------------------------------- +allows(string|Type $type): bool .[method] +----------------------------------------- The `allows()` method checks type compatibility. For example, it can determine if a value of a certain type could be passed as a parameter to a function expecting this type. @@ -197,3 +221,24 @@ $type->allows('Foo'); // false $type = Type::fromString('mixed'); $type->allows('null'); // true ``` + + +with(string|Type $type): Type .[method]{data-version:4.0.10} +------------------------------------------------------------ + +Returns a Type object that accepts both the original type and the one being added. It creates a so-called union type. + +The method is clever and does not duplicate types unnecessarily. If you add a type that is already present, or is a superset of the current type (e.g., adding `mixed` to `string`), the result is simplified. + +```php +$type = Type::fromString('string'); + +// Extending to nullable string +echo $type->with('null'); // '?string' + +// Creating a union type +echo $type->with('int'); // 'string|int' + +// Adding a type that supersedes everything +echo $type->with('mixed'); // 'mixed' +``` diff --git a/utils/es/@meta.texy b/utils/es/@meta.texy new file mode 100644 index 0000000000..1670b124ad --- /dev/null +++ b/utils/es/@meta.texy @@ -0,0 +1 @@ +{{sitename: Nette Documentación}} diff --git a/utils/es/arrays.texy b/utils/es/arrays.texy index 062f6a39d4..39497de06e 100644 --- a/utils/es/arrays.texy +++ b/utils/es/arrays.texy @@ -360,8 +360,8 @@ pick(array &$array, string|int $key, ?mixed $default=null): mixed .[method] Devuelve y elimina el valor de un elemento del array. Si no existe, lanza una excepción, o devuelve el valor `$default` si se especifica. ```php -$array = [1 => 'foo', null => 'bar']; -$a = Arrays::pick($array, null); +$array = [1 => 'foo', 'x' => 'bar']; +$a = Arrays::pick($array, 'x'); // $a = 'bar' $b = Arrays::pick($array, 'not-exists', 'foobar'); // $b = 'foobar' diff --git a/utils/fr/@meta.texy b/utils/fr/@meta.texy new file mode 100644 index 0000000000..72ae4b8db8 --- /dev/null +++ b/utils/fr/@meta.texy @@ -0,0 +1 @@ +{{sitename: Documentation Nette}} diff --git a/utils/fr/arrays.texy b/utils/fr/arrays.texy index a084df7709..140b2e2cc8 100644 --- a/utils/fr/arrays.texy +++ b/utils/fr/arrays.texy @@ -360,8 +360,8 @@ pick(array &$array, string|int $key, ?mixed $default=null): mixed .[method] Retourne et supprime la valeur de l'élément du tableau. S'il n'existe pas, lève une exception, ou retourne la valeur `$default` si elle est spécifiée. ```php -$array = [1 => 'foo', null => 'bar']; -$a = Arrays::pick($array, null); +$array = [1 => 'foo', 'x' => 'bar']; +$a = Arrays::pick($array, 'x'); // $a = 'bar' $b = Arrays::pick($array, 'not-exists', 'foobar'); // $b = 'foobar' diff --git a/utils/hu/@meta.texy b/utils/hu/@meta.texy new file mode 100644 index 0000000000..c172d1cda5 --- /dev/null +++ b/utils/hu/@meta.texy @@ -0,0 +1 @@ +{{sitename: Nette dokumentáció}} diff --git a/utils/hu/arrays.texy b/utils/hu/arrays.texy index 2a76d0ea3b..a25bf3e74f 100644 --- a/utils/hu/arrays.texy +++ b/utils/hu/arrays.texy @@ -360,8 +360,8 @@ pick(array &$array, string|int $key, ?mixed $default=null): mixed .[method] Visszaadja és eltávolítja az elem értékét a tömbből. Ha nem létezik, kivételt dob, vagy visszaadja a `$default` értéket, ha meg van adva. ```php -$array = [1 => 'foo', null => 'bar']; -$a = Arrays::pick($array, null); +$array = [1 => 'foo', 'x' => 'bar']; +$a = Arrays::pick($array, 'x'); // $a = 'bar' $b = Arrays::pick($array, 'not-exists', 'foobar'); // $b = 'foobar' diff --git a/utils/it/@meta.texy b/utils/it/@meta.texy new file mode 100644 index 0000000000..4647d0c8a2 --- /dev/null +++ b/utils/it/@meta.texy @@ -0,0 +1 @@ +{{sitename: Documentazione Nette}} diff --git a/utils/it/arrays.texy b/utils/it/arrays.texy index 1d60931cee..c2b6c5ae5c 100644 --- a/utils/it/arrays.texy +++ b/utils/it/arrays.texy @@ -360,8 +360,8 @@ pick(array &$array, string|int $key, ?mixed $default=null): mixed .[method] Restituisce e rimuove il valore di un elemento dall'array. Se non esiste, lancia un'eccezione o restituisce il valore `$default`, se specificato. ```php -$array = [1 => 'foo', null => 'bar']; -$a = Arrays::pick($array, null); +$array = [1 => 'foo', 'x' => 'bar']; +$a = Arrays::pick($array, 'x'); // $a = 'bar' $b = Arrays::pick($array, 'not-exists', 'foobar'); // $b = 'foobar' diff --git a/utils/ja/@meta.texy b/utils/ja/@meta.texy new file mode 100644 index 0000000000..d3c41dc3d7 --- /dev/null +++ b/utils/ja/@meta.texy @@ -0,0 +1 @@ +{{sitename: Nette ドキュメンテーション}} diff --git a/utils/ja/arrays.texy b/utils/ja/arrays.texy index adb4a9385c..090e2f6646 100644 --- a/utils/ja/arrays.texy +++ b/utils/ja/arrays.texy @@ -360,8 +360,8 @@ pick(array &$array, string|int $key, ?mixed $default=null): mixed .[method] 配列から要素の値を返して削除します。存在しない場合は例外をスローするか、`$default` が指定されている場合はその値を返します。 ```php -$array = [1 => 'foo', null => 'bar']; -$a = Arrays::pick($array, null); +$array = [1 => 'foo', 'x' => 'bar']; +$a = Arrays::pick($array, 'x'); // $a = 'bar' $b = Arrays::pick($array, 'not-exists', 'foobar'); // $b = 'foobar' diff --git a/utils/pl/@meta.texy b/utils/pl/@meta.texy new file mode 100644 index 0000000000..61ac92d1af --- /dev/null +++ b/utils/pl/@meta.texy @@ -0,0 +1 @@ +{{sitename: Dokumentacja Nette}} diff --git a/utils/pl/arrays.texy b/utils/pl/arrays.texy index 03b7309a65..7273b72ee4 100644 --- a/utils/pl/arrays.texy +++ b/utils/pl/arrays.texy @@ -360,8 +360,8 @@ pick(array &$array, string|int $key, ?mixed $default=null): mixed .[method] Zwraca i usuwa wartość elementu z tablicy. Jeśli nie istnieje, rzuca wyjątek lub zwraca wartość `$default`, jeśli jest podana. ```php -$array = [1 => 'foo', null => 'bar']; -$a = Arrays::pick($array, null); +$array = [1 => 'foo', 'x' => 'bar']; +$a = Arrays::pick($array, 'x'); // $a = 'bar' $b = Arrays::pick($array, 'not-exists', 'foobar'); // $b = 'foobar' diff --git a/utils/pt/@meta.texy b/utils/pt/@meta.texy new file mode 100644 index 0000000000..41a853b6aa --- /dev/null +++ b/utils/pt/@meta.texy @@ -0,0 +1 @@ +{{sitename: Documentação Nette}} diff --git a/utils/pt/arrays.texy b/utils/pt/arrays.texy index a5081dbad6..bef58ccebb 100644 --- a/utils/pt/arrays.texy +++ b/utils/pt/arrays.texy @@ -360,8 +360,8 @@ pick(array &$array, string|int $key, ?mixed $default=null): mixed .[method] Retorna e remove o valor de um elemento do array. Se não existir, lança uma exceção ou retorna o valor `$default`, se fornecido. ```php -$array = [1 => 'foo', null => 'bar']; -$a = Arrays::pick($array, null); +$array = [1 => 'foo', 'x' => 'bar']; +$a = Arrays::pick($array, 'x'); // $a = 'bar' $b = Arrays::pick($array, 'not-exists', 'foobar'); // $b = 'foobar' diff --git a/utils/ro/@meta.texy b/utils/ro/@meta.texy new file mode 100644 index 0000000000..9c744b37d6 --- /dev/null +++ b/utils/ro/@meta.texy @@ -0,0 +1 @@ +{{sitename: Documentație Nette}} diff --git a/utils/ro/arrays.texy b/utils/ro/arrays.texy index 2f998eb83a..cae59f62dd 100644 --- a/utils/ro/arrays.texy +++ b/utils/ro/arrays.texy @@ -360,8 +360,8 @@ pick(array &$array, string|int $key, ?mixed $default=null): mixed .[method] Returnează și elimină valoarea unui element din array. Dacă nu există, aruncă o excepție sau returnează valoarea `$default`, dacă este specificată. ```php -$array = [1 => 'foo', null => 'bar']; -$a = Arrays::pick($array, null); +$array = [1 => 'foo', 'x' => 'bar']; +$a = Arrays::pick($array, 'x'); // $a = 'bar' $b = Arrays::pick($array, 'not-exists', 'foobar'); // $b = 'foobar' diff --git a/utils/ru/@meta.texy b/utils/ru/@meta.texy new file mode 100644 index 0000000000..7f329adfce --- /dev/null +++ b/utils/ru/@meta.texy @@ -0,0 +1 @@ +{{sitename: Документация Nette}} diff --git a/utils/ru/arrays.texy b/utils/ru/arrays.texy index 4ba819ae5b..dec3f21649 100644 --- a/utils/ru/arrays.texy +++ b/utils/ru/arrays.texy @@ -360,8 +360,8 @@ pick(array &$array, string|int $key, mixed $default=null): mixed .[method] Возвращает и удаляет значение элемента из массива. Если он не существует, выбрасывает исключение, или возвращает значение `$default`, если оно указано. ```php -$array = [1 => 'foo', null => 'bar']; -$a = Arrays::pick($array, null); +$array = [1 => 'foo', 'x' => 'bar']; +$a = Arrays::pick($array, 'x'); // $a = 'bar' $b = Arrays::pick($array, 'not-exists', 'foobar'); // $b = 'foobar' diff --git a/utils/sl/@meta.texy b/utils/sl/@meta.texy new file mode 100644 index 0000000000..724324bee5 --- /dev/null +++ b/utils/sl/@meta.texy @@ -0,0 +1 @@ +{{sitename: Nette Dokumentacija}} diff --git a/utils/sl/arrays.texy b/utils/sl/arrays.texy index c9c044f98c..9c82a7842c 100644 --- a/utils/sl/arrays.texy +++ b/utils/sl/arrays.texy @@ -360,8 +360,8 @@ pick(array &$array, string|int $key, ?mixed $default=null): mixed .[method] Vrne in odstrani vrednost elementa iz polja. Če ne obstaja, sproži izjemo ali vrne vrednost `$default`, če je podana. ```php -$array = [1 => 'foo', null => 'bar']; -$a = Arrays::pick($array, null); +$array = [1 => 'foo', 'x' => 'bar']; +$a = Arrays::pick($array, 'x'); // $a = 'bar' $b = Arrays::pick($array, 'not-exists', 'foobar'); // $b = 'foobar' diff --git a/utils/tr/@meta.texy b/utils/tr/@meta.texy new file mode 100644 index 0000000000..8dfe82f311 --- /dev/null +++ b/utils/tr/@meta.texy @@ -0,0 +1 @@ +{{sitename: Nette Dokümantasyonu}} diff --git a/utils/tr/arrays.texy b/utils/tr/arrays.texy index aa7941b653..e47a08a863 100644 --- a/utils/tr/arrays.texy +++ b/utils/tr/arrays.texy @@ -360,8 +360,8 @@ pick(array &$array, string|int $key, ?mixed $default=null): mixed .[method] Bir öğenin değerini diziden döndürür ve kaldırır. Eğer mevcut değilse, istisna fırlatır veya belirtilmişse `$default` değerini döndürür. ```php -$array = [1 => 'foo', null => 'bar']; -$a = Arrays::pick($array, null); +$array = [1 => 'foo', 'x' => 'bar']; +$a = Arrays::pick($array, 'x'); // $a = 'bar' $b = Arrays::pick($array, 'not-exists', 'foobar'); // $b = 'foobar' diff --git a/utils/uk/@meta.texy b/utils/uk/@meta.texy new file mode 100644 index 0000000000..96e2d9752a --- /dev/null +++ b/utils/uk/@meta.texy @@ -0,0 +1 @@ +{{sitename: Документація Nette}} diff --git a/utils/uk/arrays.texy b/utils/uk/arrays.texy index 6d3a4bf31f..2a0e7fc547 100644 --- a/utils/uk/arrays.texy +++ b/utils/uk/arrays.texy @@ -360,8 +360,8 @@ pick(array &$array, string|int $key, ?mixed $default=null): mixed .[method] Повертає та видаляє значення елемента з масиву. Якщо він не існує, викликає виняток або повертає значення `$default`, якщо воно вказане. ```php -$array = [1 => 'foo', null => 'bar']; -$a = Arrays::pick($array, null); +$array = [1 => 'foo', 'x' => 'bar']; +$a = Arrays::pick($array, 'x'); // $a = 'bar' $b = Arrays::pick($array, 'not-exists', 'foobar'); // $b = 'foobar' diff --git a/www/bg/packages.texy b/www/bg/packages.texy index cc362f1f78..8915f6a226 100644 --- a/www/bg/packages.texy +++ b/www/bg/packages.texy @@ -12,7 +12,7 @@ | **Http**:[http:] | Слой, капсулиращ HTTP заявка & отговор | [GitHub |https://github.com/nette/http] [API |https://api.nette.org/http/] | **Latte**:[latte:] | Страхотна система за шаблони | [GitHub |https://github.com/nette/latte] [API |https://api.nette.org/latte/] | **Mail**:[mail:] | Изпращане на имейли | [GitHub |https://github.com/nette/mail] [API |https://api.nette.org/mail/] -| **Neon**:[neon:] | Четене и запис на формат [NEON |https://ne-on.org] | [GitHub |https://github.com/nette/neon] [API |https://api.nette.org/neon/] +| **Neon**:[neon:] | Четене и запис на формат [NEON |https://fiddle.nette.org/neon/] | [GitHub |https://github.com/nette/neon] [API |https://api.nette.org/neon/] | **Php Generator**:[php-generator:] | Генератор на PHP код | [GitHub |https://github.com/nette/php-generator] [API |https://api.nette.org/php-generator/] | **Robot Loader**:[robot-loader:] | Най-удобното автоматично зареждане | [GitHub |https://github.com/nette/robot-loader] [API |https://api.nette.org/robot-loader/] | **Routing**:[application:routing] | Маршрутизация | [GitHub |https://github.com/nette/routing] [API |https://api.nette.org/routing/] diff --git a/www/cs/packages.texy b/www/cs/packages.texy index 22e1d9d7e2..01ad3a5618 100644 --- a/www/cs/packages.texy +++ b/www/cs/packages.texy @@ -12,7 +12,7 @@ Seznam balíčků Nette | **Http**:[http:] | Vrstva zapouzdřující HTTP request & response | [GitHub |https://github.com/nette/http] [API |https://api.nette.org/http/] | **Latte**:[latte:] | Skvělý šablonovací systém | [GitHub |https://github.com/nette/latte] [API |https://api.nette.org/latte/] | **Mail**:[mail:] | Odesílání e-mailů | [GitHub |https://github.com/nette/mail] [API |https://api.nette.org/mail/] -| **Neon**:[neon:] | Čtení a zápis formátu [NEON |https://ne-on.org] | [GitHub |https://github.com/nette/neon] [API |https://api.nette.org/neon/] +| **Neon**:[neon:] | Čtení a zápis formátu [NEON |https://fiddle.nette.org/neon/] | [GitHub |https://github.com/nette/neon] [API |https://api.nette.org/neon/] | **Php Generator**:[php-generator:] | Generátor PHP kódu | [GitHub |https://github.com/nette/php-generator] [API |https://api.nette.org/php-generator/] | **Robot Loader**:[robot-loader:] | Nejkomfortnější autoloading | [GitHub |https://github.com/nette/robot-loader] [API |https://api.nette.org/robot-loader/] | **Routing**:[application:routing] | Routování | [GitHub |https://github.com/nette/routing] [API |https://api.nette.org/routing/] diff --git a/www/de/packages.texy b/www/de/packages.texy index 1eabb71e2e..da060914a0 100644 --- a/www/de/packages.texy +++ b/www/de/packages.texy @@ -12,7 +12,7 @@ Liste der Nette-Pakete | **Http**:[http:] | Schicht zur Kapselung von HTTP Request & Response | GitHub |https://github.com/nette/http] [API |https://api.nette.org/http/] | **Latte**:[latte:] | Großartiges Template-System | GitHub |https://github.com/nette/latte] [API |https://api.nette.org/latte/] | **Mail**:[mail:] | Senden von E-Mails | GitHub |https://github.com/nette/mail] [API |https://api.nette.org/mail/] -| **Neon**:[neon:] | Lesen und Schreiben des [NEON |https://ne-on.org] Formats | GitHub |https://github.com/nette/neon] [API |https://api.nette.org/neon/] +| **Neon**:[neon:] | Lesen und Schreiben des [NEON |https://fiddle.nette.org/neon/] Formats | GitHub |https://github.com/nette/neon] [API |https://api.nette.org/neon/] | **Php Generator**:[php-generator:] | PHP-Code-Generator | GitHub |https://github.com/nette/php-generator] [API |https://api.nette.org/php-generator/] | **Robot Loader**:[robot-loader:] | Das komfortabelste Autoloading | GitHub |https://github.com/nette/robot-loader] [API |https://api.nette.org/robot-loader/] | **Routing**:[application:routing] | Routing | GitHub |https://github.com/nette/routing] [API |https://api.nette.org/routing/] diff --git a/www/el/packages.texy b/www/el/packages.texy index b4289bca58..a609f055d0 100644 --- a/www/el/packages.texy +++ b/www/el/packages.texy @@ -12,7 +12,7 @@ | **Http**:[http:] | Επίπεδο που ενσωματώνει το HTTP request & response | [GitHub |https://github.com/nette/http] [API |https://api.nette.org/http/] | **Latte**:[latte:] | Εξαιρετικό σύστημα προτύπων | [GitHub |https://github.com/nette/latte] [API |https://api.nette.org/latte/] | **Mail**:[mail:] | Αποστολή e-mail | [GitHub |https://github.com/nette/mail] [API |https://api.nette.org/mail/] -| **Neon**:[neon:] | Ανάγνωση και εγγραφή της μορφής [NEON |https://ne-on.org] | [GitHub |https://github.com/nette/neon] [API |https://api.nette.org/neon/] +| **Neon**:[neon:] | Ανάγνωση και εγγραφή της μορφής [NEON |https://fiddle.nette.org/neon/] | [GitHub |https://github.com/nette/neon] [API |https://api.nette.org/neon/] | **Php Generator**:[php-generator:] | Γεννήτρια κώδικα PHP | [GitHub |https://github.com/nette/php-generator] [API |https://api.nette.org/php-generator/] | **Robot Loader**:[robot-loader:] | Η πιο άνετη αυτόματη φόρτωση | [GitHub |https://github.com/nette/robot-loader] [API |https://api.nette.org/robot-loader/] | **Routing**:[application:routing] | Δρομολόγηση | [GitHub |https://github.com/nette/routing] [API |https://api.nette.org/routing/] diff --git a/www/en/packages.texy b/www/en/packages.texy index 61945fc199..60d091be49 100644 --- a/www/en/packages.texy +++ b/www/en/packages.texy @@ -12,7 +12,7 @@ List of Packages | **Http**:[http:] | Layer encapsulating HTTP request & response | [GitHub |https://github.com/nette/http] [API |https://api.nette.org/http/] | **Latte**:[latte:] | Amazing template engine | [GitHub |https://github.com/nette/latte] [API |https://api.nette.org/latte/] | **Mail**:[mail:] | Sending emails | [GitHub |https://github.com/nette/mail] [API |https://api.nette.org/mail/] -| **Neon**:[neon:] | Reading and writing [NEON format |https://ne-on.org] | [GitHub |https://github.com/nette/neon] [API |https://api.nette.org/neon/] +| **Neon**:[neon:] | Reading and writing [NEON format |https://fiddle.nette.org/neon/] | [GitHub |https://github.com/nette/neon] [API |https://api.nette.org/neon/] | **Php Generator**:[php-generator:] | PHP code generator | [GitHub |https://github.com/nette/php-generator] [API |https://api.nette.org/php-generator/] | **Robot Loader**:[robot-loader:] | The most comfortable class autoloading | [GitHub |https://github.com/nette/robot-loader] [API |https://api.nette.org/robot-loader/] | **Routing**:[application:routing] | URL routing | [GitHub |https://github.com/nette/routing] [API |https://api.nette.org/routing/] diff --git a/www/es/packages.texy b/www/es/packages.texy index ae2279ea62..6c48cc5a33 100644 --- a/www/es/packages.texy +++ b/www/es/packages.texy @@ -12,7 +12,7 @@ Lista de paquetes de Nette | **Http**:[http:] | Capa que encapsula la petición y respuesta HTTP | [GitHub |https://github.com/nette/http] [API |https://api.nette.org/http/] | **Latte**:[latte:] | Excelente sistema de plantillas | [GitHub |https://github.com/nette/latte] [API |https://api.nette.org/latte/] | **Mail**:[mail:] | Envío de correos electrónicos | [GitHub |https://github.com/nette/mail] [API |https://api.nette.org/mail/] -| **Neon**:[neon:] | Lectura y escritura del formato [NEON |https://ne-on.org] | [GitHub |https://github.com/nette/neon] [API |https://api.nette.org/neon/] +| **Neon**:[neon:] | Lectura y escritura del formato [NEON |https://fiddle.nette.org/neon/] | [GitHub |https://github.com/nette/neon] [API |https://api.nette.org/neon/] | **Php Generator**:[php-generator:] | Generador de código PHP | [GitHub |https://github.com/nette/php-generator] [API |https://api.nette.org/php-generator/] | **Robot Loader**:[robot-loader:] | El autoloading más cómodo | [GitHub |https://github.com/nette/robot-loader] [API |https://api.nette.org/robot-loader/] | **Routing**:[application:routing] | Enrutamiento | [GitHub |https://github.com/nette/routing] [API |https://api.nette.org/routing/] diff --git a/www/fr/packages.texy b/www/fr/packages.texy index 99c919906e..ecb97d45fd 100644 --- a/www/fr/packages.texy +++ b/www/fr/packages.texy @@ -12,7 +12,7 @@ Liste des paquets Nette | **[Http |http:]** | Couche encapsulant la requête & réponse HTTP | [GitHub |https://github.com/nette/http] [API |https://api.nette.org/http/] | **[Latte |latte:]** | Excellent système de template | [GitHub |https://github.com/nette/latte] [API |https://api.nette.org/latte/] | **[Mail |mail:]** | Envoi d'e-mails | [GitHub |https://github.com/nette/mail] [API |https://api.nette.org/mail/] -| **[Neon |neon:]** | Lecture et écriture du format [NEON |https://ne-on.org] | [GitHub |https://github.com/nette/neon] [API |https://api.nette.org/neon/] +| **[Neon |neon:]** | Lecture et écriture du format [NEON |https://fiddle.nette.org/neon/] | [GitHub |https://github.com/nette/neon] [API |https://api.nette.org/neon/] | **[Php Generator |php-generator:]** | Générateur de code PHP | [GitHub |https://github.com/nette/php-generator] [API |https://api.nette.org/php-generator/] | **[Robot Loader |robot-loader:]** | Autoloading le plus confortable | [GitHub |https://github.com/nette/robot-loader] [API |https://api.nette.org/robot-loader/] | **[Routing |application:routing]** | Routage | [GitHub |https://github.com/nette/routing] [API |https://api.nette.org/routing/] diff --git a/www/hu/packages.texy b/www/hu/packages.texy index a7b9279ea5..a7045aeafa 100644 --- a/www/hu/packages.texy +++ b/www/hu/packages.texy @@ -12,7 +12,7 @@ Nette csomagok listája | **Http**:[http:] | HTTP kérést és választ beágyazó réteg | [GitHub |https://github.com/nette/http] [API |https://api.nette.org/http/] | **Latte**:[latte:] | Nagyszerű sablonrendszer | [GitHub |https://github.com/nette/latte] [API |https://api.nette.org/latte/] | **Mail**:[mail:] | E-mailek küldése | [GitHub |https://github.com/nette/mail] [API |https://api.nette.org/mail/] -| **Neon**:[neon:] | [NEON |https://ne-on.org] formátum olvasása és írása | [GitHub |https://github.com/nette/neon] [API |https://api.nette.org/neon/] +| **Neon**:[neon:] | [NEON |https://fiddle.nette.org/neon/] formátum olvasása és írása | [GitHub |https://github.com/nette/neon] [API |https://api.nette.org/neon/] | **Php Generator**:[php-generator:] | PHP kódgenerátor | [GitHub |https://github.com/nette/php-generator] [API |https://api.nette.org/php-generator/] | **Robot Loader**:[robot-loader:] | A legkényelmesebb autoloading | [GitHub |https://github.com/nette/robot-loader] [API |https://api.nette.org/robot-loader/] | **Routing**:[application:routing] | Útválasztás | [GitHub |https://github.com/nette/routing] [API |https://api.nette.org/routing/] diff --git a/www/it/packages.texy b/www/it/packages.texy index f0ba73804f..27503bc5a7 100644 --- a/www/it/packages.texy +++ b/www/it/packages.texy @@ -12,7 +12,7 @@ Elenco dei pacchetti Nette | **Http**:[http:] | Livello che incapsula HTTP request & response | [GitHub |https://github.com/nette/http] [API |https://api.nette.org/http/] | **Latte**:[latte:] | Fantastico sistema di template | [GitHub |https://github.com/nette/latte] [API |https://api.nette.org/latte/] | **Mail**:[mail:] | Invio di e-mail | [GitHub |https://github.com/nette/mail] [API |https://api.nette.org/mail/] -| **Neon**:[neon:] | Lettura e scrittura del formato [NEON |https://ne-on.org] | [GitHub |https://github.com/nette/neon] [API |https://api.nette.org/neon/] +| **Neon**:[neon:] | Lettura e scrittura del formato [NEON |https://fiddle.nette.org/neon/] | [GitHub |https://github.com/nette/neon] [API |https://api.nette.org/neon/] | **Php Generator**:[php-generator:] | Generatore di codice PHP | [GitHub |https://github.com/nette/php-generator] [API |https://api.nette.org/php-generator/] | **Robot Loader**:[robot-loader:] | L'autoloading più comodo | [GitHub |https://github.com/nette/robot-loader] [API |https://api.nette.org/robot-loader/] | **Routing**:[application:routing] | Routing | [GitHub |https://github.com/nette/routing] [API |https://api.nette.org/routing/] diff --git a/www/ja/packages.texy b/www/ja/packages.texy index f458e2463c..d968ddcccc 100644 --- a/www/ja/packages.texy +++ b/www/ja/packages.texy @@ -12,7 +12,7 @@ Netteパッケージ一覧 | **Http**:[http:] | HTTPリクエスト&レスポンスをカプセル化する層 | [GitHub |https://github.com/nette/http] [API |https://api.nette.org/http/] | **Latte**:[latte:] | 素晴らしいテンプレートシステム | [GitHub |https://github.com/nette/latte] [API |https://api.nette.org/latte/] | **Mail**:[mail:] | メール送信 | [GitHub |https://github.com/nette/mail] [API |https://api.nette.org/mail/] -| **Neon**:[neon:] | [NEON |https://ne-on.org] 形式の読み書き | [GitHub |https://github.com/nette/neon] [API |https://api.nette.org/neon/] +| **Neon**:[neon:] | [NEON |https://fiddle.nette.org/neon/] 形式の読み書き | [GitHub |https://github.com/nette/neon] [API |https://api.nette.org/neon/] | **Php Generator**:[php-generator:] | PHPコードジェネレータ | [GitHub |https://github.com/nette/php-generator] [API |https://api.nette.org/php-generator/] | **Robot Loader**:[robot-loader:] | 最も快適なオートローディング | [GitHub |https://github.com/nette/robot-loader] [API |https://api.nette.org/robot-loader/] | **Routing**:[application:routing] | ルーティング | [GitHub |https://github.com/nette/routing] [API |https://api.nette.org/routing/] diff --git a/www/pl/packages.texy b/www/pl/packages.texy index 83d35268fa..f2ad154f60 100644 --- a/www/pl/packages.texy +++ b/www/pl/packages.texy @@ -12,7 +12,7 @@ Lista pakietów Nette | **Http**:[http:] | Warstwa hermetyzująca żądanie i odpowiedź HTTP | [GitHub |https://github.com/nette/http] [API |https://api.nette.org/http/] | **Latte**:[latte:] | Doskonały system szablonów | [GitHub |https://github.com/nette/latte] [API |https://api.nette.org/latte/] | **Mail**:[mail:] | Wysyłanie e-maili | [GitHub |https://github.com/nette/mail] [API |https://api.nette.org/mail/] -| **Neon**:[neon:] | Odczyt i zapis formatu [NEON |https://ne-on.org] | [GitHub |https://github.com/nette/neon] [API |https://api.nette.org/neon/] +| **Neon**:[neon:] | Odczyt i zapis formatu [NEON |https://fiddle.nette.org/neon/] | [GitHub |https://github.com/nette/neon] [API |https://api.nette.org/neon/] | **Php Generator**:[php-generator:] | Generator kodu PHP | [GitHub |https://github.com/nette/php-generator] [API |https://api.nette.org/php-generator/] | **Robot Loader**:[robot-loader:] | Najwygodniejszy autoloading | [GitHub |https://github.com/nette/robot-loader] [API |https://api.nette.org/robot-loader/] | **Routing**:[application:routing] | Routing | [GitHub |https://github.com/nette/routing] [API |https://api.nette.org/routing/] diff --git a/www/pt/packages.texy b/www/pt/packages.texy index e017413f0a..a9c9fe63d7 100644 --- a/www/pt/packages.texy +++ b/www/pt/packages.texy @@ -12,7 +12,7 @@ Lista de Pacotes Nette | **Http**:[http:] | Camada encapsulando requisição & resposta HTTP | [GitHub |https://github.com/nette/http] [API |https://api.nette.org/http/] | **Latte**:[latte:] | Ótimo sistema de templates | [GitHub |https://github.com/nette/latte] [API |https://api.nette.org/latte/] | **Mail**:[mail:] | Envio de e-mails | [GitHub |https://github.com/nette/mail] [API |https://api.nette.org/mail/] -| **Neon**:[neon:] | Leitura e escrita do formato [NEON |https://ne-on.org] | [GitHub |https://github.com/nette/neon] [API |https://api.nette.org/neon/] +| **Neon**:[neon:] | Leitura e escrita do formato [NEON |https://fiddle.nette.org/neon/] | [GitHub |https://github.com/nette/neon] [API |https://api.nette.org/neon/] | **Php Generator**:[php-generator:] | Gerador de código PHP | [GitHub |https://github.com/nette/php-generator] [API |https://api.nette.org/php-generator/] | **Robot Loader**:[robot-loader:] | O autoloading mais confortável | [GitHub |https://github.com/nette/robot-loader] [API |https://api.nette.org/robot-loader/] | **Routing**:[application:routing] | Roteamento | [GitHub |https://github.com/nette/routing] [API |https://api.nette.org/routing/] diff --git a/www/ro/packages.texy b/www/ro/packages.texy index 6dfbb6916f..a77a3ef94a 100644 --- a/www/ro/packages.texy +++ b/www/ro/packages.texy @@ -12,7 +12,7 @@ Lista pachetelor Nette | **Http**:[http:] | Strat care încapsulează cererea & răspunsul HTTP | [GitHub |https://github.com/nette/http] [API |https://api.nette.org/http/] | **Latte**:[latte:] | Sistem excelent de șabloane | [GitHub |https://github.com/nette/latte] [API |https://api.nette.org/latte/] | **Mail**:[mail:] | Trimiterea de e-mailuri | [GitHub |https://github.com/nette/mail] [API |https://api.nette.org/mail/] -| **Neon**:[neon:] | Citirea și scrierea formatului [NEON |https://ne-on.org] | [GitHub |https://github.com/nette/neon] [API |https://api.nette.org/neon/] +| **Neon**:[neon:] | Citirea și scrierea formatului [NEON |https://fiddle.nette.org/neon/] | [GitHub |https://github.com/nette/neon] [API |https://api.nette.org/neon/] | **Php Generator**:[php-generator:] | Generator de cod PHP | [GitHub |https://github.com/nette/php-generator] [API |https://api.nette.org/php-generator/] | **Robot Loader**:[robot-loader:] | Cel mai confortabil autoloading | [GitHub |https://github.com/nette/robot-loader] [API |https://api.nette.org/robot-loader/] | **Routing**:[application:routing] | Rutare | [GitHub |https://github.com/nette/routing] [API |https://api.nette.org/routing/] diff --git a/www/ru/packages.texy b/www/ru/packages.texy index 70d68370c5..fa212efcd5 100644 --- a/www/ru/packages.texy +++ b/www/ru/packages.texy @@ -12,7 +12,7 @@ | **Http**:[http:] | Слой, инкапсулирующий HTTP request & response | [GitHub |https://github.com/nette/http] [API |https://api.nette.org/http/] | **Latte**:[latte:] | Отличная система шаблонов | [GitHub |https://github.com/nette/latte] [API |https://api.nette.org/latte/] | **Mail**:[mail:] | Отправка электронной почты | [GitHub |https://github.com/nette/mail] [API |https://api.nette.org/mail/] -| **Neon**:[neon:] | Чтение и запись формата [NEON |https://ne-on.org] | [GitHub |https://github.com/nette/neon] [API |https://api.nette.org/neon/] +| **Neon**:[neon:] | Чтение и запись формата [NEON |https://fiddle.nette.org/neon/] | [GitHub |https://github.com/nette/neon] [API |https://api.nette.org/neon/] | **Php Generator**:[php-generator:] | Генератор PHP-кода | [GitHub |https://github.com/nette/php-generator] [API |https://api.nette.org/php-generator/] | **Robot Loader**:[robot-loader:] | Самый удобный автозагрузчик | [GitHub |https://github.com/nette/robot-loader] [API |https://api.nette.org/robot-loader/] | **Routing**:[application:routing] | Маршрутизация | [GitHub |https://github.com/nette/routing] [API |https://api.nette.org/routing/] diff --git a/www/sl/packages.texy b/www/sl/packages.texy index 81a32cb6c7..9b3c556109 100644 --- a/www/sl/packages.texy +++ b/www/sl/packages.texy @@ -12,7 +12,7 @@ Seznam paketov Nette | **Http**:[http:] | Plast, ki inkapsulira HTTP zahtevo & odgovor | [GitHub |https://github.com/nette/http] [API |https://api.nette.org/http/] | **Latte**:[latte:] | Odličen sistem predlog | [GitHub |https://github.com/nette/latte] [API |https://api.nette.org/latte/] | **Mail**:[mail:] | Pošiljanje e-pošte | [GitHub |https://github.com/nette/mail] [API |https://api.nette.org/mail/] -| **Neon**:[neon:] | Branje in pisanje formata [NEON |https://ne-on.org] | [GitHub |https://github.com/nette/neon] [API |https://api.nette.org/neon/] +| **Neon**:[neon:] | Branje in pisanje formata [NEON |https://fiddle.nette.org/neon/] | [GitHub |https://github.com/nette/neon] [API |https://api.nette.org/neon/] | **Php Generator**:[php-generator:] | Generator PHP kode | [GitHub |https://github.com/nette/php-generator] [API |https://api.nette.org/php-generator/] | **Robot Loader**:[robot-loader:] | Najudobnejši autoloading | [GitHub |https://github.com/nette/robot-loader] [API |https://api.nette.org/robot-loader/] | **Routing**:[application:routing] | Usmerjanje | [GitHub |https://github.com/nette/routing] [API |https://api.nette.org/routing/] diff --git a/www/tr/packages.texy b/www/tr/packages.texy index d53e725ad0..644f78541e 100644 --- a/www/tr/packages.texy +++ b/www/tr/packages.texy @@ -12,7 +12,7 @@ Nette Paket Listesi | **Http**:[http:] | HTTP isteğini ve yanıtını kapsayan katman | [GitHub |https://github.com/nette/http] [API |https://api.nette.org/http/] | **Latte**:[latte:] | Harika şablonlama sistemi | [GitHub |https://github.com/nette/latte] [API |https://api.nette.org/latte/] | **Mail**:[mail:] | E-posta gönderme | [GitHub |https://github.com/nette/mail] [API |https://api.nette.org/mail/] -| **Neon**:[neon:] | [NEON |https://ne-on.org] formatını okuma ve yazma | [GitHub |https://github.com/nette/neon] [API |https://api.nette.org/neon/] +| **Neon**:[neon:] | [NEON |https://fiddle.nette.org/neon/] formatını okuma ve yazma | [GitHub |https://github.com/nette/neon] [API |https://api.nette.org/neon/] | **Php Generator**:[php-generator:] | PHP kodu oluşturucu | [GitHub |https://github.com/nette/php-generator] [API |https://api.nette.org/php-generator/] | **Robot Loader**:[robot-loader:] | En konforlu otomatik yükleme | [GitHub |https://github.com/nette/robot-loader] [API |https://api.nette.org/robot-loader/] | **Routing**:[application:routing] | Yönlendirme | [GitHub |https://github.com/nette/routing] [API |https://api.nette.org/routing/] diff --git a/www/uk/packages.texy b/www/uk/packages.texy index 0e639722d6..983e47f622 100644 --- a/www/uk/packages.texy +++ b/www/uk/packages.texy @@ -12,7 +12,7 @@ | **Http**:[http:] | Шар, що інкапсулює HTTP request & response | [GitHub |https://github.com/nette/http] [API |https://api.nette.org/http/] | **Latte**:[latte:] | Чудова система шаблонів | [GitHub |https://github.com/nette/latte] [API |https://api.nette.org/latte/] | **Mail**:[mail:] | Надсилання електронних листів | [GitHub |https://github.com/nette/mail] [API |https://api.nette.org/mail/] -| **Neon**:[neon:] | Читання та запис формату [NEON |https://ne-on.org] | [GitHub |https://github.com/nette/neon] [API |https://api.nette.org/neon/] +| **Neon**:[neon:] | Читання та запис формату [NEON |https://fiddle.nette.org/neon/] | [GitHub |https://github.com/nette/neon] [API |https://api.nette.org/neon/] | **Php Generator**:[php-generator:] | Генератор PHP коду | [GitHub |https://github.com/nette/php-generator] [API |https://api.nette.org/php-generator/] | **Robot Loader**:[robot-loader:] | Найкомфортніше автозавантаження | [GitHub |https://github.com/nette/robot-loader] [API |https://api.nette.org/robot-loader/] | **Routing**:[application:routing] | Маршрутизація | [GitHub |https://github.com/nette/routing] [API |https://api.nette.org/routing/]