PHP Classes

File: extension/core/phase4.go

Recommend this page to a friend!
  Packages of Roni   Easy-Excel   extension/core/phase4.go   Download  
File: extension/core/phase4.go
Role: Auxiliary data
Content type: text/plain
Description: Auxiliary data
Class: Easy-Excel
Export and read XLSX files with a PHP Go extension
Author: By
Last change:
Date: 7 days ago
Size: 4,800 bytes
 

Contents

Class file image Download
package core import ( "encoding/json" "fmt" "time" "github.com/xuri/excelize/v2" ) // Phase 4.1 (PLAN.md §13): document properties, unmerge, merge introspection. // Workbook encryption lives in the save/open paths (workbook.go), value // binders and print titles are PHP-side. // docPropsSpec mirrors PhpSpreadsheet's Document\Properties; company/manager // live in app.xml. type docPropsSpec struct { Title string `json:"title"` Subject string `json:"subject"` Creator string `json:"creator"` LastModifiedBy string `json:"lastModifiedBy"` Description string `json:"description"` Keywords string `json:"keywords"` Category string `json:"category"` Company string `json:"company"` // app.xml; excelize exposes no Manager field Created string `json:"created"` // RFC 3339 Modified string `json:"modified"` } // SetDocProps writes core (and, when set, app) document properties; the // docProps parts are workbook-level, safe in any mode. func (w *Workbook) SetDocProps(jsonSpec string) error { w.mu.Lock() defer w.mu.Unlock() if w.closed { return errClosed } var spec docPropsSpec if err := json.Unmarshal([]byte(jsonSpec), &spec); err != nil { return fmt.Errorf("easy-excel: invalid document properties: %w", err) } if err := w.f.SetDocProps(&excelize.DocProperties{ Title: spec.Title, Subject: spec.Subject, Creator: spec.Creator, LastModifiedBy: spec.LastModifiedBy, Description: spec.Description, Keywords: spec.Keywords, Category: spec.Category, Created: spec.Created, Modified: spec.Modified, }); err != nil { return err } if spec.Company != "" { return w.f.SetAppProps(&excelize.AppProperties{ Application: "easy-excel", Company: spec.Company, }) } return nil } // customPropSpec is one custom document property. Type is PhpSpreadsheet's // single-letter code (b/i/f/d/s); Remove deletes the property. type customPropSpec struct { Name string `json:"name"` Value any `json:"value"` Type string `json:"type"` Remove bool `json:"remove"` } // SetCustomProp writes (or removes) one custom document property. func (w *Workbook) SetCustomProp(jsonSpec string) error { w.mu.Lock() defer w.mu.Unlock() if w.closed { return errClosed } var spec customPropSpec if err := json.Unmarshal([]byte(jsonSpec), &spec); err != nil { return fmt.Errorf("easy-excel: invalid custom property: %w", err) } if spec.Name == "" { return fmt.Errorf("easy-excel: custom property needs a name") } prop := excelize.CustomProperty{Name: spec.Name} if !spec.Remove { prop.Value = customPropValue(spec.Value, spec.Type) } return w.f.SetCustomProps(prop) } // customPropValue coerces a JSON value to the Go type excelize stores per the // PhpSpreadsheet type code (JSON numbers arrive as float64). func customPropValue(v any, typ string) any { switch typ { case "b": b, _ := v.(bool) return b case "i": if f, ok := v.(float64); ok { return int32(f) // excelize accepts int32, not int } case "f": if f, ok := v.(float64); ok { return f } case "d": if s, ok := v.(string); ok { if t, err := time.Parse(time.RFC3339, s); err == nil { return t } } } if s, ok := v.(string); ok { return s } return fmt.Sprintf("%v", v) } // UnmergeCells removes a merge. Merges queued for the StreamWriter but not // yet applied are simply dropped; everything else unmerges at save. func (w *Workbook) UnmergeCells(sheet, ref string) error { w.mu.Lock() defer w.mu.Unlock() if w.closed { return errClosed } st, err := w.state(sheet) if err != nil { return err } tl, br, err := splitRange(ref) if err != nil { return err } kept := st.preMerges[:0] dropped := false for _, m := range st.preMerges { if m[0] == tl && m[1] == br { dropped = true continue } kept = append(kept, m) } st.preMerges = kept if dropped { return nil } if st.random() { if err := w.mutable(); err != nil { return err } return w.f.UnmergeCell(sheet, tl, br) } st.pending = append(st.pending, pendingOp{kind: opUnmerge, ref: tl + ":" + br}) return nil } // Merges returns the sheet's merged ranges ("A1:C3"). Reading degrades a // streaming sheet, like every other read. func (w *Workbook) Merges(sheet string) ([]string, error) { w.mu.Lock() defer w.mu.Unlock() if w.closed { return nil, errClosed } st, err := w.state(sheet) if err != nil { return nil, err } if err := w.ensureRandom(sheet, st); err != nil { return nil, err } merged, err := w.f.GetMergeCells(sheet) if err != nil { return nil, err } out := make([]string, 0, len(merged)) for _, m := range merged { out = append(out, m.GetStartAxis()+":"+m.GetEndAxis()) } return out, nil }