Skip to content

d3vnicolas/button-color-command

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

10 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Módulo Button Color Changer - Alteração de Cor de Botões por Store-View

Processo de Concepção e Desenvolvimento

1. Análise dos Requisitos

Durante a análise inicial, identifiquei os seguintes pontos críticos que precisavam ser resolvidos:

  1. Interface de Usuário: Precisava de uma forma simples para o cliente alterar cores sem conhecimento técnico
  2. Validação de Entrada: Garantir que apenas cores HEX válidas e store-views existentes fossem aceitas
  3. Armazenamento de Configuração: Decidir onde e como armazenar a cor configurada por store-view
  4. Aplicação no Frontend: Como aplicar a cor customizada a todos os botões sem modificar arquivos do tema
  5. Persistência: Garantir que a configuração seja mantida e aplicada corretamente

2. Decisões de Arquitetura

2.1 Estrutura do Módulo

Decidi criar um módulo Magento 2 seguindo as melhores práticas do framework, dividindo as responsabilidades em componentes claros:

  • Comando CLI: Para receber e processar os parâmetros do usuário
  • Sistema de Configuração: Para armazenar a cor por store-view
  • Block: Para encapsular a lógica de geração de CSS
  • Layout XML: Para injetar o CSS no head de todas as páginas
  • Template: Para renderizar o CSS de forma segura

2.2 Estrutura de Arquivos

app/code/Devnicolas/ButtonColor/
├── registration.php                          # Registro do módulo no Magento
├── etc/
│   ├── module.xml                            # Declaração do módulo e dependências
│   └── di.xml                                # Registro do comando de console no DI
├── Console/
│   └── Command/
│       └── ChangeButtonColor.php             # Comando CLI principal
├── Block/
│   └── ButtonColor.php                       # Block que gera CSS customizado
├── view/
│   └── frontend/
│       ├── layout/
│       │   └── default.xml                   # Layout XML para injetar CSS no head
│       └── templates/
│           └── button-color.phtml            # Template que renderiza o CSS
└── README.md                                 # Este arquivo

6.2 Componentes Principais

registration.php

  • Registra o módulo no sistema Magento usando ComponentRegistrar
  • Define o namespace do módulo como Devnicolas_ButtonColor

etc/module.xml

  • Declara o módulo e suas dependências
  • Dependências: Magento_Store (para gerenciar stores) e Magento_Theme (para temas e layouts)

etc/di.xml

  • Registra o comando de console no sistema de Dependency Injection do Magento
  • Conecta o comando color:change à classe ChangeButtonColor

Console/Command/ChangeButtonColor.php

  • Classe principal do comando CLI
  • Responsabilidades:
    • Receber e validar argumentos (cor HEX e ID da store-view)
    • Normalizar formato de cor HEX (aceita com ou sem #)
    • Validar formato HEX (6 caracteres hexadecimais)
    • Validar existência da store-view usando StoreRepositoryInterface
    • Salvar configuração usando WriterInterface com scope stores
    • Remover configuração usando flag --reset para restaurar cores originais
    • Limpar cache de configuração após salvar ou remover
    • Exibir mensagens de sucesso/erro ao usuário

Block/ButtonColor.php

  • Block que lê a configuração da store-view atual
  • Responsabilidades:
    • Obter cor configurada usando ScopeConfigInterface com scope stores
    • Gerar CSS customizado que sobrescreve cores de todos os botões
    • Retornar CSS formatado para injeção no template

view/frontend/layout/default.xml

  • Layout XML que injeta o block no <head> de todas as páginas
  • Utiliza o handle default para garantir que o CSS seja carregado em todas as páginas

view/frontend/templates/button-color.phtml

  • Template que renderiza o CSS inline no <head>
  • Verifica se há cor configurada antes de renderizar
  • Utiliza @noEscape para permitir renderização de CSS (com segurança controlada)

7. Fluxo de Execução

7.1 Fluxo do Comando CLI

Fluxo de Alteração de Cor:

  1. Execução do Comando

    • Cliente executa: ./bin/magento color:change 000000 1
    • Symfony Console recebe os argumentos
  2. Validação de Cor HEX

    • Remove # se presente
    • Converte para maiúsculas
    • Valida formato usando regex /^[0-9A-F]{6}$/i
    • Retorna erro se formato inválido
  3. Validação de Store-View

    • Converte ID para inteiro
    • Verifica se é numérico
    • Usa StoreRepositoryInterface::getById() para verificar existência
    • Retorna erro se store-view não existir
  4. Salvamento da Configuração

    • Usa WriterInterface::save() com:
      • Path: devnicolas/button_color/color
      • Scope: ScopeInterface::SCOPE_STORES
      • Scope ID: ID da store-view
    • Limpa cache de configuração usando CacheManager
  5. Feedback ao Usuário

    • Exibe mensagem de sucesso com cor e nome da store
    • Confirma limpeza de cache

Fluxo de Reset (--reset):

  1. Execução do Comando

    • Cliente executa: ./bin/magento color:change --reset 1
    • Symfony Console detecta a flag --reset
  2. Validação de Store-View

    • Converte ID para inteiro
    • Verifica se é numérico
    • Usa StoreRepositoryInterface::getById() para verificar existência
    • Retorna erro se store-view não existir
  3. Remoção da Configuração

    • Usa WriterInterface::delete() com:
      • Path: devnicolas/button_color/color
      • Scope: ScopeInterface::SCOPE_STORES
      • Scope ID: ID da store-view
    • Remove registro do banco de dados
    • Limpa cache de configuração usando CacheManager
  4. Feedback ao Usuário

    • Exibe mensagem de sucesso confirmando reset
    • Confirma remoção de estilos inline e limpeza de cache

7.2 Fluxo de Renderização no Frontend

  1. Carregamento da Página

    • Magento carrega o layout default.xml
    • O block button.color.css é adicionado ao <head>
  2. Obtenção da Cor Configurada

    • Block ButtonColor obtém a store atual via StoreManager
    • Lê configuração usando ScopeConfigInterface com scope stores
    • Retorna null se não houver cor configurada
  3. Geração de CSS

    • Se cor configurada existe, gera CSS que targeta:
      • button (todos os botões)
      • .action.primary (botões primários do Magento)
      • .btn-primary (botões primários Bootstrap)
      • [class*="button"] (qualquer elemento com "button" no nome da classe)
      • Variações de botões primários e secundários
    • Aplica !important para garantir sobrescrita
    • Inclui estilos para hover
  4. Renderização

    • Template verifica se há cor configurada
    • Renderiza tag <style> com CSS customizado
    • CSS é injetado no <head> da página

3. Decisões de Design Detalhadas

3.1 Por que usar Sistema de Configuração do Magento?

Decisão: Utilizei o sistema nativo de configuração do Magento (WriterInterface e ScopeConfigInterface)

Razão:

  • Escopo por Store-View: Permite diferentes cores para cada store-view, atendendo exatamente ao requisito do teste
  • Cache Nativo: Integra-se perfeitamente com o sistema de cache do Magento, garantindo performance
  • Persistência: Dados são salvos no banco de dados na tabela core_config_data, garantindo que a configuração seja mantida mesmo após limpezas de cache
  • Padrão Magento: Segue as melhores práticas do framework, tornando o código mais manutenível e compatível com futuras versões

Implementação:

$this->configWriter->save(
    self::CONFIG_PATH,
    $hexColor,
    ScopeInterface::SCOPE_STORES,
    $storeViewId
);

3.2 Por que injetar CSS via Layout XML?

Decisão: Injetar CSS inline através de um Block adicionado ao head.additional via layout XML

Razão:

  • Universalidade: CSS é aplicado em todas as páginas automaticamente, sem necessidade de modificar cada template
  • Performance: CSS inline é carregado imediatamente, sem requisição HTTP adicional, melhorando o tempo de carregamento
  • Simplicidade: Não requer modificação de arquivos LESS/CSS do tema, mantendo o tema limpo e facilitando atualizações
  • Flexibilidade: Pode ser facilmente removido ou modificado sem afetar o tema base

Implementação:

<referenceBlock name="head.additional">
    <block class="Devnicolas\ButtonColor\Block\ButtonColor" 
           name="button.color.css" 
           template="Devnicolas_ButtonColor::button-color.phtml"/>
</referenceBlock>

3.3 Por que usar !important no CSS?

Decisão: Aplicar !important em todas as propriedades CSS geradas

Razão:

  • Garantia de Sobrescrita: Garante que a cor customizada sobrescreva estilos do tema, mesmo aqueles com alta especificidade CSS
  • Compatibilidade: Funciona com qualquer tema, sem necessidade de conhecer a estrutura CSS específica de cada tema
  • Simplicidade: Evita necessidade de calcular especificidade CSS ou criar seletores muito específicos, tornando o código mais simples e manutenível

Implementação:

button,
.action.primary,
.btn-primary {
    background-color: #000000 !important;
    border-color: #000000 !important;
}

3.4 Por que validar formato HEX?

Decisão: Implementar validação rigorosa do formato HEX usando regex

Razão:

  • Segurança: Previne injeção de código malicioso através de valores não validados. Se não validasse, um usuário poderia tentar injetar código JavaScript ou CSS malicioso
  • Consistência: Garante formato padronizado, facilitando o processamento e evitando erros
  • Experiência do Usuário: Fornece feedback claro sobre erros, ajudando o cliente a corrigir o problema rapidamente

Implementação:

private function isValidHexColor(string $hexColor): bool
{
    return preg_match('/^[0-9A-F]{6}$/i', $hexColor) === 1;
}

3.5 Por que limpar cache após salvar?

Decisão: Limpar automaticamente o cache de configuração após salvar ou remover a configuração

Razão:

  • Aplicação Imediata: Mudanças são visíveis imediatamente no frontend, sem necessidade de o cliente executar comandos adicionais
  • Consistência: Garante que a configuração seja lida corretamente do banco de dados, evitando problemas com cache desatualizado
  • Melhor Experiência: Cliente vê resultado instantaneamente, melhorando a experiência de uso do módulo

Implementação:

$this->cacheManager->clean([\Magento\Framework\App\Cache\Type\Config::TYPE_IDENTIFIER]);

3.6 Por que aceitar cor com ou sem #?

Decisão: Normalizar a cor HEX para aceitar tanto 000000 quanto #000000

Razão:

  • Flexibilidade: Permite que o cliente use o formato que preferir, tornando o comando mais intuitivo
  • Experiência do Usuário: Reduz erros comuns, como esquecer ou adicionar o # incorretamente
  • Compatibilidade: Funciona com diferentes formatos de entrada, tornando o módulo mais robusto

Implementação:

private function normalizeHexColor(string $hexColor): string
{
    $hexColor = trim($hexColor);
    $hexColor = ltrim($hexColor, '#');
    return strtoupper($hexColor);
}

4. Desafios Encontrados e Soluções

Desafio 1: Garantir Sobrescrita de Estilos do Tema

Problema: Inicialmente, tentei aplicar a cor sem usar !important, mas alguns temas têm estilos muito específicos que não eram sobrescritos. Isso fazia com que a cor customizada não fosse aplicada em alguns botões.

Solução: Utilizei !important em todas as propriedades CSS geradas. Isso garante que a cor customizada sempre sobrescreva os estilos do tema, independentemente da especificidade CSS.

Desafio 2: Targetar Todos os Botões

Problema: Diferentes temas e módulos usam diferentes classes CSS para botões. Se eu targetasse apenas button, muitos botões não seriam afetados.

Solução: Criei uma lista abrangente de seletores CSS que targeta:

  • button (todos os elementos button)
  • .action.primary (botões primários do Magento)
  • .btn-primary (botões primários Bootstrap)
  • [class*="button"] (qualquer elemento com "button" no nome da classe)
  • Variações de botões primários e secundários

Isso garante cobertura completa, independentemente do tema usado.

Desafio 3: Validação de Store-View

Problema: Precisava validar se a store-view existe antes de salvar a configuração, mas não queria que o comando falhasse silenciosamente ou com mensagens confusas.

Solução: Utilizei StoreRepositoryInterface::getById() que lança uma exceção NoSuchEntityException se a store não existir. Capturei essa exceção e exibi uma mensagem de erro clara e amigável ao usuário.

Desafio 4: Aplicação Imediata da Cor

Problema: Após salvar a configuração, o cache do Magento poderia não ser atualizado imediatamente, fazendo com que a cor não aparecesse no frontend.

Solução: Implementei limpeza automática do cache de configuração após salvar ou remover a configuração. Isso garante que as mudanças sejam visíveis imediatamente.

Desafio 5: Funcionalidade de Reset

Problema: O teste original não mencionava reset, mas percebi que seria útil permitir que o cliente remova a cor customizada e volte às cores originais do tema.

Solução: Adicionei a flag --reset ao comando, que remove a configuração do banco de dados. Quando não há configuração, o template não renderiza CSS, permitindo que os estilos originais do tema sejam aplicados.

5. Implementação Técnica Detalhada

5.1 Validação de Cor HEX

private function normalizeHexColor(string $hexColor): string
{
    $hexColor = trim($hexColor);
    $hexColor = ltrim($hexColor, '#');
    return strtoupper($hexColor);
}

private function isValidHexColor(string $hexColor): bool
{
    return preg_match('/^[0-9A-F]{6}$/i', $hexColor) === 1;
}

Decisões:

  • Aceita cor com ou sem #
  • Normaliza para maiúsculas para consistência
  • Valida exatamente 6 caracteres hexadecimais

5.2 Geração de CSS

public function getButtonColorCss(): string
{
    $color = $this->getButtonColor();
    if (!$color) {
        return '';
    }

    $hexColor = '#' . ltrim($color, '#');
    
    // CSS que targeta múltiplos seletores de botões
    // Aplica background-color e border-color
    // Inclui estados hover
}

Decisões:

  • Targeta múltiplos seletores para garantir cobertura completa
  • Aplica tanto background-color quanto border-color para consistência visual
  • Inclui estado hover com opacidade reduzida para feedback visual

5.3 Armazenamento de Configuração

Salvamento:

$this->configWriter->save(
    self::CONFIG_PATH,
    $hexColor,
    ScopeInterface::SCOPE_STORES,
    $storeViewId
);

Remoção (reset):

$this->configWriter->delete(
    self::CONFIG_PATH,
    ScopeInterface::SCOPE_STORES,
    $storeViewId
);

Decisões:

  • Path: devnicolas/button_color/color (namespace do módulo)
  • Scope: SCOPE_STORES permite configuração por store-view
  • Scope ID: ID da store-view permite múltiplas configurações
  • Remoção via delete() remove completamente a configuração, fazendo com que o template não renderize CSS

6. Arquitetura do Módulo

6.1 Estrutura de Arquivos

app/code/Devnicolas/ButtonColor/
├── registration.php                          # Registro do módulo no Magento
├── etc/
│   ├── module.xml                            # Declaração do módulo e dependências
│   └── di.xml                                # Registro do comando de console no DI
├── Console/
│   └── Command/
│       └── ChangeButtonColor.php             # Comando CLI principal
├── Block/
│   └── ButtonColor.php                       # Block que gera CSS customizado
├── view/
│   └── frontend/
│       ├── layout/
│       │   └── default.xml                   # Layout XML para injetar CSS no head
│       └── templates/
│           └── button-color.phtml            # Template que renderiza o CSS
└── README.md                                 # Este arquivo
button,
.action.primary,
.btn-primary,
[class*="button"],
/* ... outros seletores ... */
{
    background-color: #000000 !important;
    border-color: #000000 !important;
}

button:hover,
.action.primary:hover,
/* ... outros seletores ... */
{
    background-color: #000000 !important;
    border-color: #000000 !important;
    opacity: 0.9;
}

8. Exemplo de Uso

8.1 Cenário do Teste Original

Para validar que o módulo funciona conforme o teste original:

  1. Executar o comando:

    ./bin/magento color:change 000000 1
  2. Verificar resultado:

    • Todos os botões da store-view ID 1 devem aparecer pretos
    • A mudança deve ser visível imediatamente no frontend
    • A configuração deve ser persistida

Alterar cor para preto na store-view 1 (Cenário do Teste):

./bin/magento color:change 000000 1

Resultado esperado:

  1. Comando valida que 000000 é um HEX válido
  2. Comando valida que store-view ID 1 existe
  3. Configuração é salva no banco de dados
  4. Cache é limpo automaticamente
  5. Mensagem de sucesso é exibida
  6. Ao acessar a loja, todos os botões aparecem pretos

Remover cor customizada e restaurar cores originais:

./bin/magento color:change --reset 1

Resultado esperado:

  1. Comando valida que store-view ID 1 existe
  2. Configuração é removida do banco de dados
  3. Cache é limpo automaticamente
  4. Mensagem de sucesso é exibida
  5. Ao acessar a loja, os botões voltam a usar as cores originais do tema

8.2 CSS Gerado

Quando uma cor é configurada, o seguinte CSS é gerado e injetado no <head>:

button,
.action.primary,
.btn-primary,
[class*="button"],
/* ... outros seletores ... */
{
    background-color: #000000 !important;
    border-color: #000000 !important;
}

button:hover,
.action.primary:hover,
/* ... outros seletores ... */
{
    background-color: #000000 !important;
    border-color: #000000 !important;
    opacity: 0.9;
}

8.3 Exemplos Adicionais

9. Instalação e Ativação

  1. Copiar o módulo para app/code/Devnicolas/ButtonColor/
  2. Executar:
    php bin/magento module:enable Devnicolas_ButtonColor
    php bin/magento setup:upgrade
    php bin/magento cache:flush

10. Uso do Comando

Sintaxe:

./bin/magento color:change <hexColor> <storeViewId>
./bin/magento color:change --reset <storeViewId>

Parâmetros:

  • hexColor: Cor hexadecimal (com ou sem #). Exemplos: 000000, #000000, FF5733, #FF5733
    • Obrigatório quando não usar --reset
  • storeViewId: ID numérico da store-view. Exemplo: 1, 2, 3
    • Obrigatório em todos os casos
  • --reset ou -r: Flag para remover a configuração de cor customizada e restaurar as cores originais dos botões
    • Remove os estilos inline do frontend
    • Remove a configuração do banco de dados
    • Quando usada, não é necessário fornecer hexColor

Alterar cor para vermelho na store-view 2:

./bin/magento color:change FF0000 2

Alterar cor para azul na store-view 3 (com #):

./bin/magento color:change #0066CC 3

Remover cor customizada e restaurar cores originais na store-view 1:

./bin/magento color:change --reset 1

ou usando a forma curta:

./bin/magento color:change -r 1

Validações:

Cor inválida:

$ ./bin/magento color:change xyz123 1
Invalid hex color format. Please provide a valid 6-character hexadecimal color (e.g., 000000 or #000000).

Store-view inexistente:

$ ./bin/magento color:change 000000 999
Store view with ID 999 does not exist.

Sucesso (alteração de cor):

$ ./bin/magento color:change 000000 1
Button color successfully changed to #000000 for store view "Default Store View" (ID: 1).
Configuration cache has been cleared.

Sucesso (reset):

$ ./bin/magento color:change --reset 1
Button color configuration successfully reset for store view "Default Store View" (ID: 1).
Inline styles have been removed. Configuration cache has been cleared.

11. Considerações Técnicas

11.1 Performance

  • CSS inline é carregado uma vez por página
  • Configuração é lida do cache do Magento
  • Não há impacto significativo no tempo de carregamento

11.2 Segurança

  • Validação rigorosa de formato HEX previne injeção de código
  • Uso de @noEscape é controlado e seguro (apenas CSS gerado internamente)
  • Validação de store-view previne acesso não autorizado

11.3 Compatibilidade

  • Funciona com qualquer tema do Magento 2
  • Não requer modificação de arquivos do tema
  • Compatível com diferentes versões do Magento 2

11.4 Cache

  • Cache de configuração é limpo automaticamente após alteração
  • Cliente pode precisar limpar cache do navegador para ver mudanças imediatamente
  • Cache de página pode precisar ser limpo em alguns casos

12. Limitações e Considerações

12.1 Limitações Conhecidas

  • CSS inline pode não sobrescrever estilos muito específicos de alguns temas
  • Requer limpeza de cache do navegador em alguns casos
  • Não modifica cores de botões carregados via JavaScript dinamicamente

12.2 Melhorias Futuras Possíveis

  • Adicionar suporte para cores de hover customizadas
  • Adicionar suporte para cores de texto dos botões
  • Adicionar interface administrativa para gerenciar cores
  • Adicionar preview de cores antes de aplicar
  • Adicionar histórico de cores utilizadas
  • Adicionar suporte para gradientes
  • Adicionar validação de contraste para acessibilidade

13. Troubleshooting

Problema: Cor não está sendo aplicada

Soluções:

  • Limpar cache: php bin/magento cache:flush
  • Verificar se store-view ID está correto
  • Verificar se cor foi salva: php bin/magento config:show devnicolas/button_color/color --scope=stores --scope-code=1
  • Limpar cache do navegador

Problema: Comando retorna erro de store-view não encontrada

Soluções:

  • Verificar IDs de store-views: php bin/magento store:list
  • Usar ID numérico correto

Problema: CSS não aparece no head

Soluções:

  • Verificar se módulo está habilitado: php bin/magento module:status Devnicolas_ButtonColor
  • Limpar cache de layout: php bin/magento cache:clean layout
  • Verificar se template está sendo carregado

Problema: Quero remover a cor customizada e voltar às cores originais

Solução:

  • Use a flag --reset com o ID da store-view:
    ./bin/magento color:change --reset 1
  • Isso remove a configuração do banco de dados e os estilos inline não serão mais renderizados

14. Estrutura de Dados

Configuração Armazenada

  • Tabela: core_config_data
  • Path: devnicolas/button_color/color
  • Scope: stores
  • Scope ID: ID da store-view
  • Value: Cor HEX (sem #, maiúsculas)

Exemplo de Registro:

path: devnicolas/button_color/color
scope: stores
scope_id: 1
value: 000000

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 2

  •  
  •