ikinci temizlik tamamlandı
This commit is contained in:
@@ -0,0 +1,513 @@
|
||||
# ExcelRowHandler Service Guide
|
||||
|
||||
## Overview
|
||||
|
||||
The `ExcelRowHandler` service is a modern, object-oriented replacement for the `addRowInTable` helper function. It provides a clean and maintainable way to add formatted rows to Excel sheets in the Register Creator system.
|
||||
|
||||
## Location
|
||||
|
||||
- **Service Class**: `App\Services\RegisterCreator\ExcelRowHandler`
|
||||
- **Integration**: `App\Services\RegisterCreator\DocumentProcessors\AbstractDocumentProcessor`
|
||||
|
||||
## Features
|
||||
|
||||
- ✅ **Duplicate Detection**: Automatically prevents duplicate report entries
|
||||
- ✅ **File Management**: Handles PDF and XLSX file copying with smart overwrite logic
|
||||
- ✅ **Page Counting**: Automatically counts PDF pages using pdftk
|
||||
- ✅ **Excel Formatting**: Preserves styles, formulas, merged cells, and row heights
|
||||
- ✅ **Comprehensive Logging**: Provides detailed logging with emoji indicators
|
||||
- ✅ **Statistics Tracking**: Tracks file types and successful operations
|
||||
- ✅ **Type Safety**: Full PHP type hints for better IDE support and error prevention
|
||||
|
||||
## Architecture
|
||||
|
||||
### Service Class: ExcelRowHandler
|
||||
|
||||
The main service class handles all row addition operations:
|
||||
|
||||
```php
|
||||
use App\Services\RegisterCreator\ExcelRowHandler;
|
||||
|
||||
$handler = new ExcelRowHandler();
|
||||
|
||||
$newRow = $handler->addRow(
|
||||
$search, // Array of file paths to search
|
||||
$selectDocument, // Document information array
|
||||
$fullFolder, // Target folder path
|
||||
$lineNumber, // Line identifier
|
||||
$documentDate, // Document date
|
||||
$rowNo, // Row sequence number
|
||||
$sheet, // PhpSpreadsheet Worksheet object
|
||||
$currentRow, // Current row position
|
||||
$override // Whether to overwrite existing files
|
||||
);
|
||||
```
|
||||
|
||||
### Integration with AbstractDocumentProcessor
|
||||
|
||||
The service is integrated into `AbstractDocumentProcessor` for easy use in all document processors:
|
||||
|
||||
```php
|
||||
protected function addRowToExcel(
|
||||
array $search,
|
||||
string $lineNumber,
|
||||
string $documentDate,
|
||||
int $rowNo
|
||||
): int
|
||||
```
|
||||
|
||||
## Usage in Document Processors
|
||||
|
||||
### Basic Usage Example
|
||||
|
||||
Here's how to use the service in a document processor:
|
||||
|
||||
```php
|
||||
class MyDocumentProcessor extends AbstractDocumentProcessor
|
||||
{
|
||||
public function process(
|
||||
array $weldLogData,
|
||||
array $document,
|
||||
Worksheet $sheet,
|
||||
int &$currentRow,
|
||||
array $settings
|
||||
): int {
|
||||
// Initialize processor (this creates the ExcelRowHandler instance)
|
||||
$this->initialize($weldLogData, $document, $sheet, $currentRow, $settings);
|
||||
|
||||
// Get line identifier
|
||||
$lineIdentifier = $weldLogData[$this->registerColumnBased];
|
||||
|
||||
// Search for files
|
||||
$search = $this->searchFiles("{$document['path']}/*{$lineIdentifier}*.pdf");
|
||||
|
||||
// Get document date
|
||||
$placeholderReplacer = new \App\Services\RegisterCreator\PlaceholderReplacer();
|
||||
$documentDate = $placeholderReplacer->getLatestDate($weldLogData, $this->registerColumnBased);
|
||||
|
||||
// Add row to Excel using the service
|
||||
$newRow = $this->addRowToExcel(
|
||||
$search,
|
||||
$lineIdentifier,
|
||||
$documentDate,
|
||||
1 // Row number in sequence
|
||||
);
|
||||
|
||||
if ($newRow > $currentRow) {
|
||||
$currentRow = $newRow;
|
||||
}
|
||||
|
||||
return $currentRow;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Real Example: DrawingsProcessor
|
||||
|
||||
```php
|
||||
class DrawingsProcessor extends AbstractDocumentProcessor
|
||||
{
|
||||
public function process(
|
||||
array $weldLogData,
|
||||
array $document,
|
||||
Worksheet $sheet,
|
||||
int &$currentRow,
|
||||
array $settings
|
||||
): int {
|
||||
$this->initialize($weldLogData, $document, $sheet, $currentRow, $settings);
|
||||
|
||||
$this->log("Processing Drawings");
|
||||
|
||||
$lineIdentifier = $weldLogData[$this->registerColumnBased];
|
||||
$normalized = $this->normalizeSearchTerm($lineIdentifier);
|
||||
$search = $this->searchFiles("{$document['path']}/*{$normalized}*.pdf");
|
||||
|
||||
$placeholderReplacer = new \App\Services\RegisterCreator\PlaceholderReplacer();
|
||||
$documentDate = $placeholderReplacer->getLatestDate($weldLogData, $this->registerColumnBased);
|
||||
|
||||
// Use the new ExcelRowHandler service method
|
||||
$newRow = $this->addRowToExcel(
|
||||
$search,
|
||||
$lineIdentifier,
|
||||
$documentDate,
|
||||
1
|
||||
);
|
||||
|
||||
if ($newRow > $currentRow) {
|
||||
$currentRow = $newRow;
|
||||
}
|
||||
|
||||
return $currentRow;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Method Parameters
|
||||
|
||||
### addRow() Method
|
||||
|
||||
| Parameter | Type | Description |
|
||||
|-----------|------|-------------|
|
||||
| `$search` | `array` | Array of file paths to search for |
|
||||
| `$selectDocument` | `array` | Document information containing title, path, type, order, etc. |
|
||||
| `$fullFolder` | `string` | Target folder path (e.g., "storage/documents/project/line/") |
|
||||
| `$lineNumber` | `string` | Line number or identifier |
|
||||
| `$documentDate` | `string` | Document date |
|
||||
| `$rowNo` | `int` | Row sequence number |
|
||||
| `$sheet` | `Worksheet` | PhpSpreadsheet Worksheet object (passed by reference) |
|
||||
| `$currentRow` | `int` | Current row position in Excel |
|
||||
| `$override` | `bool` | Whether to overwrite existing files (default: false) |
|
||||
|
||||
**Returns**: `int` - Next row position
|
||||
|
||||
### addRowToExcel() Helper Method
|
||||
|
||||
| Parameter | Type | Description |
|
||||
|-----------|------|-------------|
|
||||
| `$search` | `array` | Array of file paths to search for |
|
||||
| `$lineNumber` | `string` | Line number or identifier |
|
||||
| `$documentDate` | `string` | Document date |
|
||||
| `$rowNo` | `int` | Row sequence number |
|
||||
|
||||
**Returns**: `int` - Next row position
|
||||
|
||||
## Document Information Structure
|
||||
|
||||
The `$selectDocument` array should contain:
|
||||
|
||||
```php
|
||||
[
|
||||
'title1' => 'Main title',
|
||||
'title2' => 'NDT Report Number',
|
||||
'title3' => 'PDF Document Title',
|
||||
'title4' => 'NDT Register Title',
|
||||
'path' => 'storage/documents/...',
|
||||
'type' => 'drawing|template|...',
|
||||
'order' => 0, // Display order
|
||||
'file_name' => 'Custom file name (optional)',
|
||||
'incoming_control_description' => 'Description (optional)'
|
||||
]
|
||||
```
|
||||
|
||||
## Excel Template Placeholders
|
||||
|
||||
The service replaces the following placeholders in the Excel template:
|
||||
|
||||
| Placeholder | Description |
|
||||
|-------------|-------------|
|
||||
| `{rowNo}` | Row sequence number |
|
||||
| `{type_order_no}` | Document type order number (e.g., 1 for QA, 2 for WDB) |
|
||||
| `{sub_number}` | Sub-number within document type (1, 2, 3...) |
|
||||
| `{full_number}` | Combined number in format "type_order_no.sub_number" (e.g., "1.1", "1.2", "3.1") |
|
||||
| `{rowTitle}` | Document title (processed) |
|
||||
| `{documentReportNumber}` | Line number/identifier |
|
||||
| `{documentDate}` | Formatted document date |
|
||||
| `{constructor}` | Contractor name |
|
||||
| `{pageCount}` | Number of pages in PDF |
|
||||
| `{pageIndex}` | Page range (e.g., "1-3") |
|
||||
| `{title1}` | Document title 1 |
|
||||
| `{ndt_report_no}` | NDT report number (title2) |
|
||||
| `{pdf_document_title}` | PDF document title (title3) |
|
||||
| `{ndt_register_title}` | NDT register title (title4) |
|
||||
|
||||
## Log Format
|
||||
|
||||
The service generates structured logs with emoji indicators:
|
||||
|
||||
```
|
||||
📋 1. Document Title - LINE001 | 1 file(s)
|
||||
-- filename.pdf
|
||||
📁 File: copied
|
||||
|
||||
📋 2. Another Document - LINE002 | 2 file(s)
|
||||
-- document1.pdf
|
||||
-- document2.pdf
|
||||
📁 File: updated
|
||||
📊 XLSX: copied
|
||||
|
||||
❌ 3. Missing Document - LINE003 | NO FILES FOUND
|
||||
Search paths:
|
||||
-- expected_filename.pdf
|
||||
|
||||
🔄 DUPLICATE: Report Title - LINE001
|
||||
```
|
||||
|
||||
### Log Indicators
|
||||
|
||||
- 📋 = Document processed
|
||||
- ✅ = Success
|
||||
- ❌ = Error or not found
|
||||
- 🔄 = Duplicate (skipped)
|
||||
- 📁 = PDF file operation
|
||||
- 📊 = XLSX file operation
|
||||
- ❓ = Warning or missing optional file
|
||||
|
||||
### File Copy Status
|
||||
|
||||
- `copied` = New file copied
|
||||
- `updated` = File content changed, updated
|
||||
- `overwritten` = File forcefully overwritten (override=true)
|
||||
- `same content, skipped` = File exists with same content, no action needed
|
||||
|
||||
## File Management
|
||||
|
||||
### PDF Files
|
||||
|
||||
All PDF files are automatically:
|
||||
1. Validated for existence
|
||||
2. Page counted using pdftk
|
||||
3. Copied to target location
|
||||
4. Named according to order and title
|
||||
|
||||
### XLSX Files (Templates)
|
||||
|
||||
For documents with type="template":
|
||||
1. Searches for corresponding .xlsx file
|
||||
2. Copies alongside PDF if found
|
||||
3. Logs result (found/not found)
|
||||
|
||||
### Smart Copy Logic
|
||||
|
||||
The service uses MD5 hash comparison to avoid unnecessary file operations:
|
||||
- If file exists and content is identical → skip
|
||||
- If file exists and content differs → update
|
||||
- If override flag is true → always overwrite
|
||||
|
||||
## Statistics
|
||||
|
||||
The service tracks statistics that can be accessed statically:
|
||||
|
||||
```php
|
||||
// Get file type statistics
|
||||
$stats = ExcelRowHandler::getFileTypeStats();
|
||||
// Returns: ['pdf' => 150, 'xlsx' => 25, ...]
|
||||
|
||||
// Get successful operations count
|
||||
$count = ExcelRowHandler::getSuccessfulOperations();
|
||||
// Returns: 150
|
||||
|
||||
// Reset statistics
|
||||
ExcelRowHandler::resetStatistics();
|
||||
```
|
||||
|
||||
## Duplicate Prevention
|
||||
|
||||
The service automatically prevents duplicate entries based on:
|
||||
- Document title (title2)
|
||||
- Line number
|
||||
|
||||
If a duplicate is detected:
|
||||
1. Row is skipped
|
||||
2. Duplicate log is written
|
||||
3. Original row position is returned (no increment)
|
||||
|
||||
## Error Handling
|
||||
|
||||
The service handles errors gracefully:
|
||||
|
||||
```php
|
||||
try {
|
||||
$newRow = $this->addRowToExcel($search, $lineNumber, $documentDate, 1);
|
||||
} catch (\Throwable $th) {
|
||||
// Error is logged automatically
|
||||
// Exception is re-thrown for upstream handling
|
||||
}
|
||||
```
|
||||
|
||||
### Error Logging
|
||||
|
||||
All errors are logged to:
|
||||
1. Laravel log (with context)
|
||||
2. Project-specific log.txt file
|
||||
3. Console output
|
||||
|
||||
## Cache Dependencies
|
||||
|
||||
The service relies on cached values:
|
||||
|
||||
| Cache Key | Description |
|
||||
|-----------|-------------|
|
||||
| `rc_contractor` | Contractor name |
|
||||
| `rc_firstPage` | First page number |
|
||||
| `rc_lastPage` | Last page number |
|
||||
| `rc_template_row` | Template row number |
|
||||
|
||||
These are managed by `RegisterCreatorService`.
|
||||
|
||||
## Migration from addRowInTable Helper
|
||||
|
||||
### Old Way (Helper Function)
|
||||
|
||||
```php
|
||||
$newRow = addRowInTable(
|
||||
$search,
|
||||
$document,
|
||||
$this->getFullFolder(),
|
||||
$lineIdentifier,
|
||||
$documentDate,
|
||||
1,
|
||||
$this->sheet,
|
||||
$currentRow,
|
||||
$this->settings['override'] ?? true
|
||||
);
|
||||
```
|
||||
|
||||
### New Way (Service Method)
|
||||
|
||||
```php
|
||||
$newRow = $this->addRowToExcel(
|
||||
$search,
|
||||
$lineIdentifier,
|
||||
$documentDate,
|
||||
1
|
||||
);
|
||||
```
|
||||
|
||||
### Benefits of Migration
|
||||
|
||||
1. **Cleaner Code**: Less parameters, more intuitive
|
||||
2. **Better Testability**: Service can be mocked and tested
|
||||
3. **Type Safety**: Full type hints
|
||||
4. **Object-Oriented**: Follows SOLID principles
|
||||
5. **Easier Maintenance**: All logic in one place
|
||||
6. **Better IDE Support**: Autocomplete and hints
|
||||
|
||||
## Best Practices
|
||||
|
||||
### 1. Always Initialize
|
||||
|
||||
```php
|
||||
$this->initialize($weldLogData, $document, $sheet, $currentRow, $settings);
|
||||
```
|
||||
|
||||
This creates the ExcelRowHandler instance and sets up necessary properties.
|
||||
|
||||
### 2. Update Current Row
|
||||
|
||||
```php
|
||||
$newRow = $this->addRowToExcel(...);
|
||||
|
||||
if ($newRow > $currentRow) {
|
||||
$currentRow = $newRow;
|
||||
}
|
||||
```
|
||||
|
||||
Always check if row was actually added before updating position.
|
||||
|
||||
### 3. Handle Search Results
|
||||
|
||||
```php
|
||||
$search = $this->searchFiles("{$document['path']}/*{$normalized}*.pdf");
|
||||
|
||||
if (empty($search)) {
|
||||
$this->log("No files found for pattern", "warning");
|
||||
return $currentRow;
|
||||
}
|
||||
```
|
||||
|
||||
Check if files exist before calling addRowToExcel.
|
||||
|
||||
### 4. Use Normalized Search Terms
|
||||
|
||||
```php
|
||||
$normalized = $this->normalizeSearchTerm($lineIdentifier);
|
||||
$search = $this->searchFiles("{$document['path']}/*{$normalized}*.pdf");
|
||||
```
|
||||
|
||||
Normalize search terms for better file matching.
|
||||
|
||||
### 5. Log Processing Steps
|
||||
|
||||
```php
|
||||
$this->log("Processing Drawings");
|
||||
$newRow = $this->addRowToExcel(...);
|
||||
$this->log("Drawings processed successfully");
|
||||
```
|
||||
|
||||
Use the log() method for consistent logging.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Files Not Found
|
||||
|
||||
1. Check file paths in search array
|
||||
2. Verify storage permissions
|
||||
3. Check if files exist in expected location
|
||||
4. Review log.txt for exact search paths
|
||||
|
||||
### Duplicate Detection Issues
|
||||
|
||||
1. Check title2 field consistency
|
||||
2. Verify line number format
|
||||
3. Reset statistics if testing: `ExcelRowHandler::resetStatistics()`
|
||||
|
||||
### Page Count Issues
|
||||
|
||||
1. Ensure pdftk is installed: `which pdftk`
|
||||
2. Check LANG environment variable
|
||||
3. Verify PDF file is not corrupted
|
||||
|
||||
### Excel Formatting Issues
|
||||
|
||||
1. Verify template row is set correctly
|
||||
2. Check placeholder names match exactly
|
||||
3. Ensure template has proper merged cells
|
||||
|
||||
## Performance Considerations
|
||||
|
||||
1. **File Operations**: Uses Laravel Storage for efficiency
|
||||
2. **MD5 Comparison**: Only calculates when necessary
|
||||
3. **Static Properties**: Shared across instances for statistics
|
||||
4. **Lazy Loading**: PDFs only opened when needed
|
||||
|
||||
## Testing
|
||||
|
||||
Example test structure:
|
||||
|
||||
```php
|
||||
use Tests\TestCase;
|
||||
use App\Services\RegisterCreator\ExcelRowHandler;
|
||||
|
||||
class ExcelRowHandlerTest extends TestCase
|
||||
{
|
||||
public function test_adds_row_successfully()
|
||||
{
|
||||
$handler = new ExcelRowHandler();
|
||||
|
||||
// Setup test data
|
||||
$search = ['storage/documents/test.pdf'];
|
||||
$document = ['title2' => 'Test', 'order' => 0, ...];
|
||||
|
||||
// Execute
|
||||
$newRow = $handler->addRow(
|
||||
$search,
|
||||
$document,
|
||||
'storage/documents/test/',
|
||||
'LINE001',
|
||||
'2024-01-01',
|
||||
1,
|
||||
$this->mockSheet,
|
||||
10,
|
||||
false
|
||||
);
|
||||
|
||||
// Assert
|
||||
$this->assertEquals(11, $newRow);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- [Register Creator Guide](./register-creator-guide.md)
|
||||
- [Save Trigger System Guide](./save-trigger-system-guide.md)
|
||||
- [Document Processors](./document-processors-guide.md)
|
||||
|
||||
## Version History
|
||||
|
||||
- **v1.0** (2024-10): Initial release
|
||||
- Migrated from addRowInTable helper function
|
||||
- Added full type hints
|
||||
- Improved error handling
|
||||
- Added statistics tracking
|
||||
|
||||
Reference in New Issue
Block a user